1569 二项式系数的个数

给定一个质数p和整数α,A。请计算有多少对(n,k)满足0≤k≤n≤A 且 (nk)(nk) 是 pαpα 的倍数。

答案比较大,对 109+7109+7 取余再输出。

 (nk)(nk) 的意思是从n个东西中选k个的方法数。

样例解释:

在这个样例中,能被4整除的是 (41)=4(41)=4  , (43)=4(43)=4   和  (63)=20(63)=20 。


 

输入

单组测试数据。
第一行有两个整数 p 和α (1≤p,α≤10^9, p 是质数)。
第二行有一个整数A (0≤A<10^1000),不含前导0。

输出

输出答案占一行。

输入样例

样例输入1
2 2
7

输出样例

样例输出1
3

知道kummer定理后直接数位dp就好了。 
设f[i,j,0/1,0/1]表示有多少个数对(x,y)从高到低做到第i位,进位了j次,x+y的前i位是否卡着A的上界,下一位是否必须要进位。 
直接转移即可。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;

cs int mod=1e9+7,inv2=mod+1>>1;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline void Dec(int &a,int b){(a-=b)<0&&(a+=mod);}
inline int c2(int n){return mul(mul(n,n-1),inv2);}

cs int N=3.5e3+5;

char s[N];
ll c[N],b[N];
int f[N][N][2][2];

int p,q;

inline void work(){
	ll x=0;
	for(int re i=1;i<=c[0];++i){
		c[i]+=x*10;
		x=c[i]%p,c[i]/=p;
	}
	int j=1;b[++b[0]]=x;
	while(j<=c[0]&&!c[j])++j;
	if(j>c[0])c[0]=0;
	else {
		for(int re i=j;i<=c[0];++i)c[i-j+1]=c[i];
		c[0]-=j-1;
	}
}

signed main(){
#ifdef zxyoi
	freopen("binom.in","r",stdin);
#endif
	scanf("%d%d",&p,&q);
	scanf("%s",s+1);c[0]=strlen(s+1);
	for(int re i=1;i<=c[0];++i)c[i]=s[i]^48;
	while(c[0])work();
	if(q>b[0])std::cout<<"0\n",exit(0);
	f[b[0]+1][0][0][1]=1;int cp1=c2(p+1),cp0=c2(p);
	for(int re i=b[0];i;--i){
		int x=b[i];
		int x1=c2(x+1),x0=c2(x),px=mul(p,x);
		for(int re j=0;j<=b[0]-i;++j){
			if(f[i+1][j][0][0]){
				int v=f[i+1][j][0][0];
				Inc(f[i][j][0][0],mul(v,cp1));
				Inc(f[i][j+1][1][0],mul(v,cp0));
			}
			if(f[i+1][j][1][0]){
				int v=f[i+1][j][1][0];
				Inc(f[i][j][0][0],mul(v,cp0));
				Inc(f[i][j+1][1][0],mul(v,cp1));
			}
			if(f[i+1][j][0][1]){
				int v=f[i+1][j][0][1];
				Inc(f[i][j][0][0],mul(v,x1));
				Inc(f[i][j][0][1],mul(v,x+1));
				Inc(f[i][j+1][1][0],mul(v,x0));
				Inc(f[i][j+1][1][1],mul(v,x));
			}
			if(f[i+1][j][1][1]){
				int v=f[i+1][j][1][1];
				Inc(f[i][j][0][0],mul(v,dec(px,x1)));
				Inc(f[i][j][0][1],mul(v,p-x-1));
				Inc(f[i][j+1][1][0],mul(v,dec(px,x0)));
				Inc(f[i][j+1][1][1],mul(v,p-x));
			}
		}
	}
	int ans=0;
	for(int re i=q;i<=b[0];++i)Inc(ans,add(f[1][i][0][1],f[1][i][0][0]));
	std::cout<<ans<<"\n";
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值