首先你得知道什么是库默尔定理:

对于 $n\choose n+m$ 和一个质数 $p$ ,存在一个最大的 $a$ 使得 $p^a|{n\choose n+m}$ ,有 $a=f(n+m,p)$ ,其中 $f(a,b)$ 表示 $a$ 在 $b$ 进制下的进位次数。

于是可以数位 $\rm{DP}$ 出所有合法的 $n+m$ ,然后计算方案数。

设 $dp(i,0/1,0/1,j)$ ,表示做到了从高到低第 $i$ 位,这 $i$ 位是否均达到上限,第 $i+1$ 位 (比 $i$ 一位) 是否向 $i$ 进位,到目前为止一共进位了 $j$ 次的方案数。

转移时乘上这一位新增的数分配给 $n,m$ 的方案数即可。

#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N=3.5e3+5;
const int mod=1e9+7;

ll res[N+5];
int P,L,n,num[N],f[2][2][N],g[2][2][N];
char str[N];

namespace _ {
    inline int mul(int x,int y) {return 1ll*x*y%mod;}
    inline int del(int x,int y) {x-=y;if(x<0) x+=mod;return x;}
    inline int add(int x,int y) {x+=y;if(x>=mod) x-=mod;return x;}
    inline void inc(int&x,int y) {x+=y;if(x>=mod) x-=mod;}
    template <typename _Tp> inline void IN(_Tp&x) {
        char ch;bool flag=0;x=0;
        while(ch=getchar(),!isdigit(ch)) if(ch=='-') flag=1;
        while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
        if(flag) x=-x;
    }
}using namespace _;

inline void pre() {
    IN(P),IN(L),scanf("%s\n",str+1),n=strlen(str+1);
    if(!P) {puts("0");exit(0);}
    for(int i=1;i<=n;++i) num[i]=str[n-i+1]-'0';
    for(int i=n;i>=1;--i) {
        for(int j=1;j<N;++j) res[j]*=10;
        res[1]+=num[i];
        for(int j=1;j<N;++j) if(res[j]>=P) res[j+1]+=res[j]/P,res[j]%=P;
    }
    for(int i=1;i<(n=N);++i) num[i]=res[i];
    while(n&&!num[n-1]) --n;
}

int main() {
    pre();
    f[1][0][0]=1;
    for(int i=n-1;i;--i) {
        int t0=(ll)P*(P+1)/2%mod;
        int t1=(ll)P*(P-1)/2%mod;
        int t2=(ll)num[i]*(num[i]+1)/2%mod;
        int t3=(ll)num[i]*(num[i]-1)/2%mod;
        int t4=(ll)num[i]*(P+P-num[i]-1)/2%mod;
        int t5=(ll)num[i]*(P+P-num[i]+1)/2%mod;
        memset(g,0,sizeof(g));
        for(int j=0;j<n-i;++j) {
            int f0=f[0][0][j],f1=f[0][1][j],f2=f[1][0][j],f3=f[1][1][j];
            inc(g[0][0][j],add(mul(f0,t0),mul(f2,t2)));
            inc(g[0][1][j],add(mul(f0,t1),mul(f2,t3)));
            inc(g[1][0][j],mul(f2,num[i]+1)),
            inc(g[1][1][j],mul(f2,num[i])),
            inc(g[0][0][j+1],add(mul(f1,t1),mul(f3,t4))),
            inc(g[0][1][j+1],add(mul(f1,t0),mul(f3,t5))),
            inc(g[1][0][j+1],mul(f3,P-num[i]-1)),
            inc(g[1][1][j+1],mul(f3,P-num[i]));
        }
        swap(f,g);
    }
    int ans=0;
    for(int i=L;i<=n;++i) inc(ans,add(f[0][0][i],f[1][0][i]));
    printf("%d\n",ans);
    return 0;
}
分类: 文章

Qiuly

QAQ

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code