题目大意
给定质数p和正整数α、k,求多少对(n,k)满足0≤m≤n≤α 且 Cmn 是 pk 的倍数
p,k≤
109
n≤
101000
分析
此题要用到库默尔定理:设m,n为正整数,p为素数,则
Cnm+n
含p的幂次等于p进制下m与n相加的进位次数。
有了这个定理就可以很好地解题了。先把n转化为p进制,然后考虑数位DP。设f[i][j][x][y],表示从高到低确定了p进制下n,m的前i位,进了j次位,x和y是01状态,分别表示前i位之和是否与n在p进制下的前i位完全相同、第i+1位是否进了位到第i位。然后转移需要分类讨论。
由于n在10进制下只有1000位,所以当p=2时只有3000多位。足以通过此题。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=3405,mo=1e9+7;
typedef long long LL;
int a[N],b[N],c[N],f[N][N][2][2],p,k,cnt,n,m,ans;
char s[N];
int main()
{
scanf("%d%d%s",&p,&k,s);
n=strlen(s);
for (int i=0;i<n;i++) a[n-i]=s[i]-'0';
for (m=0;!(n==1 && a[1]==0);)
{
int res=0;
memset(c,0,sizeof(c));
for (int i=n;i;i--)
{
c[i]=((LL)res*10+a[i])/p;
res=((LL)res*10+a[i])%p;
}
b[m++]=res;
memcpy(a,c,sizeof(a));
for (;n>1 && !a[n];n--);
}
f[m][0][1][0]=1;
for (int i=m-1;i>=0;i--)
{
for (int j=0;j<m-i;j++)
{
int t00=(LL)p*(p+1)/2%mo,t01=(LL)(p-1)*p/2%mo,t10=((LL)p*p-t00)%mo,t11=((LL)p*p-t01)%mo;
f[i][j][0][0]=(f[i][j][0][0]+(LL)f[i+1][j][0][0]*t00+(LL)f[i+1][j][0][1]*t10)%mo;
f[i][j+1][0][1]=(f[i][j+1][0][1]+(LL)f[i+1][j][0][0]*t01+(LL)f[i+1][j][0][1]*t11)%mo;
if (!b[i])
{
f[i][j][1][0]=(f[i][j][1][0]+f[i+1][j][1][0]+(LL)f[i+1][j][1][1]*(p-1))%mo;
f[i][j+1][1][1]=(f[i][j+1][1][1]+(LL)f[i+1][j][1][1]*p)%mo;
continue;
}
t00=(LL)b[i]*(b[i]+1)/2%mo; t01=(LL)(b[i]-1)*b[i]/2%mo;
t10=(LL)(p+p-b[i]-1)*b[i]/2%mo; t11=(LL)(p+p-b[i]+1)*b[i]/2%mo;
f[i][j][0][0]=(f[i][j][0][0]+(LL)f[i+1][j][1][0]*t00+(LL)f[i+1][j][1][1]*t10)%mo;
f[i][j+1][0][1]=(f[i][j+1][0][1]+(LL)f[i+1][j][1][0]*t01+(LL)f[i+1][j][1][1]*t11)%mo;
f[i][j][1][0]=(f[i][j][1][0]+(LL)f[i+1][j][1][0]*(b[i]+1)+(LL)f[i+1][j][1][1]*(p-b[i]-1))%mo;
f[i][j+1][1][1]=(f[i][j+1][1][1]+(LL)f[i+1][j][1][0]*b[i]+(LL)f[i+1][j][1][1]*(p-b[i]))%mo;
}
}
ans=0;
for (int i=k;i<=m;i++) ans=(ans+f[0][i][0][0]+(LL)f[0][i][1][0])%mo;
printf("%d\n",ans);
return 0;
}