51nod1245 Binomial Coefficients Revenge
题目来源: HackerRank
基准时间限制:2 秒 空间限制:131072 KB 分值: 640
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的倍数......。
例如:M = 10, P = 2。C(10,0) -> C(10,10)
分别为:1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1。
P的幂 = 1 2 4 8 16......
1 45 45 1 这4个数只能整除1。
10 210 210 10这4个数能整除2但不能整除4。
252 能整除4但不能整除8。
120 120 这2个数能整除8但不能整除16。
所以输出:4 4 1 2。
Input
第1行:一个数T,表示输入的测试数量(1 <= T <= 5000)
第2 - T + 1行:每行2个数,M和P,中间用空格分隔(2 <= M, P <= 10^18)
Output
输出共T行,每行若干个数,中间用空格分隔,对应组合数的数量。
Input示例
3
4 5
6 3
10 2
Output示例
5
3 4
4 4 1 2
数学 kummer定理 数位DP
又是奇怪的定理题
kummer定理:设m,n为正整数,p为素数,则C(下m+n上m)含p的幂次等于m+n在p进制下的进位次数。
设$ f[i][j][0/1] $表示当前考虑了低i位,已有的幂次为j(即已经进位j次),当前位是否大于n。
然后就可以愉快(并不)地数位DP了
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #define LL long long 7 using namespace std; 8 const int mxn=85; 9 LL read(){ 10 LL x=0,f=1;char ch=getchar(); 11 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0' && ch<='9'){x=x*10-'0'+ch;ch=getchar();} 13 return x*f; 14 } 15 int n; 16 LL m,P; 17 int a[mxn]; 18 LL f[mxn][mxn][2]; 19 void solve(){ 20 n=0; 21 LL bas=m; 22 while(m){ 23 a[++n]=m%P; 24 m/=P; 25 } 26 f[0][0][0]=1; 27 int i,j; 28 for(i=1;i<=n;i++){ 29 for(j=0;j<=i;j++){ 30 f[i][j][0]=f[i-1][j][0]*(a[i]+1)+(j?f[i-1][j-1][1]*a[i]:0); 31 f[i][j][1]=f[i-1][j][0]*(P-a[i]-1)+(j?f[i-1][j-1][1]*(P-a[i]):0); 32 } 33 } 34 LL now=0; 35 for(i=0;i>=0;i++){ 36 printf("%lld ",f[n][i][0]); 37 now+=f[n][i][0]; 38 if(now>bas-1)break; 39 } 40 puts(""); 41 return; 42 } 43 int main(){ 44 int i,j; 45 int T=read(); 46 while(T--){ 47 m=read();P=read(); 48 solve(); 49 } 50 return 0; 51 }
本文为博主原创文章,转载请注明出处。