【Codeforces 582D】Number of Binominal Coefficients

数位 DP。

题目大意:

给定质数 $p$ 和 整数 $\alpha$,大整数 $A$,求有多少对 $n,k$ 满足 $0\leq k\leq n\leq A$ 且 $p^\alpha|\binom{n}{k}$。

题解:

我们考虑如何求 $\binom{n}{m}$ 中含有的质因子 $p$ 个数。

不难发现,对每个 $i$,它对质因子个数的贡献只可能为 $0$ 或 $1$。

而是否产生贡献,取决于 $m$ 和 $n-m$ 在 $p$ 进制下做加法的第 $i$ 位是否进位。

于是,我们先将 $A$ 转化为 $p$ 进制,然后进行数位 DP 即可。

令 $f[n][m][0/1][0/1]$ 表示当前考虑到第 $n$ 位,之前已经进位 $m$ 次,前面考虑的位是否紧贴上界,最后考虑的这位是否需要从下一位进 $1$。

然后转移分一些情况讨论即可。

最后对于进位次数大于等于 $\alpha$ 且最低位不进位的方案求和即可。

时间复杂度 $O(|A|^2)$。

Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=5005,md=1e9+7;
int p,alpha,n;
int A[N],ans;
inline void add(int&a,const LL&b){a=(a+b)%md;}
void Read(){
    char s[N],t[N];
    scanf("%s",s);
    int lens=strlen(s);
    for(int i=0;i<lens;++i)s[i]^='0';
    while(1){
        LL d=0;int lent=0;
        for(int i=0;i<lens;++i){
            d=d*10+s[i];
            t[lent++]=d/p,d-=d/p*p;
        }
        int beg=0;
        while(t[beg]==0&&beg<lent)++beg;
        A[n++]=d;
        if(lent==beg)return;
        for(int i=beg;i<lent;++i)
        s[i-beg]=t[i];
        lens=lent-beg;
    }
}
int f[2][N][2][2];
int a1,a2,a3,a4;
inline int calc(int x){
    if(x<p)return(x+1LL)*(x+2)/2%md;
    return(a1-calc(2*p-3-x)+md)%md;
}
void calc(){
    a1=(LL)p*p%md,a3=calc(p-1),a2=(a1-a3+md)%md,a4=calc(p-2);
    f[0][0][0][0]=calc(A[0]-1);
    f[0][1][0][1]=calc(A[0]-2);
    f[0][0][1][0]=A[0]+1;
    f[0][1][1][1]=A[0];
    for(int i=1;i<n;i++){
        memset(f[i&1],0,sizeof*f);
        for(int c=0;c<=alpha;++c){
            const int t=min(c+1,alpha);
            const int&P=f[i&1^1][c][0][0];
            add(f[i&1][c][0][0],(LL)P*a3);
            add(f[i&1][t][0][1],(LL)P*a4);
            const int&Q=f[i&1^1][c][0][1];
            add(f[i&1][c][0][0],(LL)Q*(a1-a3+md));
            add(f[i&1][t][0][1],(LL)Q*(a1-a4+md));
            const int&X=f[i&1^1][c][1][0];
            add(f[i&1][c][0][0],(LL)X*calc(A[i]-1));
            add(f[i&1][t][0][1],(LL)X*calc(A[i]-2));
            add(f[i&1][c][1][0],(LL)X*(A[i]+1));
            add(f[i&1][t][1][1],(LL)X*A[i]);
            const int&Y=f[i&1^1][c][1][1];
            add(f[i&1][c][0][0],(LL)Y*(calc(A[i]+p-1)-a3+md));
            add(f[i&1][t][0][1],(LL)Y*(calc(A[i]+p-2)-a4+md));
            add(f[i&1][c][1][0],(LL)Y*(p-A[i]-1));
            add(f[i&1][t][1][1],(LL)Y*(p-A[i]));
        }
    }
    ans=(f[n&1^1][alpha][0][0]+f[n&1^1][alpha][1][0])%md;
}
int main(){
    scanf("%d%d",&p,&alpha);
    if(alpha>5000)return puts("0")&0;
    Read();
    reverse(A,A+n);
    calc();
    printf("%d\n",ans);
    return 0;
}