题意
C(M,N) = M! / N! / (M - N)! (组合数)。给出M和质数p,求C(M,0), C(M,1)……C(M,M)这M + 1个数中,有多少数不是p的倍数,有多少是p的倍数但不是p^2的倍数,有多少是p^2的倍数但不是p^3的倍数……。
1 <= T <= 5000,2 <= M, P <= 10^18
分析
去学习了一发kummer定理,简称库默尔定理。大概就是说
然后就可以愉快的数位dp了。设f[i,j,0/1]表示从低到高做到第i位,进位了j次且该位是否进位的方案,转移显然。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL n,p,a[65],f[65][65][2];
void solve()
{
LL tmp=n;int a1=0;
while (tmp) a[++a1]=tmp%p,tmp/=p;
memset(f,0,sizeof(f));
f[0][0][0]=1;
for (int i=1;i<=a1;i++)
{
f[i][0][0]=f[i-1][0][0]*(a[i]+1);
for (int j=1;j<=a1;j++)
{
f[i][j][0]=f[i-1][j][0]*(a[i]+1)+f[i-1][j][1]*a[i];
f[i][j][1]=f[i-1][j-1][0]*(p-a[i]-1)+f[i-1][j-1][1]*(p-a[i]);
}
}
for (int i=0;i<=a1&&f[a1][i][0];i++) printf("%lld ",f[a1][i][0]);
puts("");
}
int main()
{
int T;scanf("%d",&T);
while (T--)
{
scanf("%lld%lld",&n,&p);
solve();
}
return 0;
}