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 }

 

posted @ 2017-06-18 20:21  SilverNebula  阅读(205)  评论(0编辑  收藏  举报
AmazingCounters.com