51nod 1245 Binomial Coefficients Revenge

1245 Binomial Coefficients Revenge
题目来源: HackerRank
基准时间限制:2 秒 空间限制:131072 KB 分值: 640 难度:8级算法题 收藏 关注
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定理
设m,n为正整数,p为素数,则 C(m+nm) 含p的幂次等于m+n在p进制下的进位次数。
所以这题就是给定n,要求对于每一个m,C(n-m)在p进制下的进位次数
于是我们把n用p进制表示, dp[i][j][0/1] 表示在n的p进制下从低位往高位的第i位,总共进位了j次,当前数<=n(0)还是>n(1)时的贡献。

pj 的答案就是 dp[cnt][j][0]


【代码】

//51nod 
#include<bits/stdc++.h>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=105;
ll T,n,p;
ll dp[mxn][mxn][2],digit[mxn];
int main()
{
    int i,j,k,cnt;
    scanf("%lld",&T);
    while(T--)
    {
        cnt=0,M(dp);
        scanf("%lld%lld",&n,&p);
        while(n) digit[++cnt]=n%p,n/=p;
        dp[1][0][0]=digit[1]+1;
        dp[1][1][1]=p-digit[1]-1;
        fo(i,1,cnt-1)
        {
            ll x=digit[i+1];
            fo(j,0,cnt)
            {
                dp[i+1][j][0]+=(x+1)*dp[i][j][0]+x*dp[i][j][1];
                dp[i+1][j+1][1]+=(p-x-1)*dp[i][j][0]+(p-x)*dp[i][j][1];
            }
        }
        for(k=cnt;dp[cnt][k][0]==0;k--);
        fo(j,0,k) printf("%lld ",dp[cnt][j][0]);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值