Problem 3. comb
Input file: comb.in
Output file: comb.out
Time limit: 1 second
Memory limit: 256 MB
一天,Mr. Ding 对组合数产生了兴趣,他想要知道满足下面条件的数i 有多少个:
gcd=( C( n , i ) , p ) = p ;
其中p 是素数。
Input
第1 行,2 个整数:n p。
Output
输出所求。
Sample
comb.in comb.out
5 2 2
Note
样例中,一共有6 个组合数:1; 5; 10; 10; 5; 1,其中和2 公约数为2 的数有两个10,故输出2。
? 对于30% 的数据,满足1<=n,p <=10^3
? 对于100% 的数据,满足1<=n, p <= 10^18
题解:
首先看到条件gcd( C ( n ,i ),p )=p,所以我们可以得到这样一个事实:
p | C ( n , i )----》C ( n , i ) % p =0
由于p是一个素数,所以可以通过Lucas对其进行分解,则可以得到 p | C ( n1 , i1 ) C ( n2 , i2 ) .....C ( nk , ik ) , 我们知道Lucas中满足当n<i时 C ( n , i ) = 0 ,所以我们很难确定在p | C ( n1 , i1 ) C ( n2 , i2 ) .....C ( nk , ik ) 中是哪一个组合数为0, 所以我们不妨换一个思路,因为p ? C ( n1 , i1 ) C ( n2 , i2 ) .....C ( nk , ik )很好求,我们求出满足p ? C ( n1 , i1 ) C ( n2 , i2 ) .....C ( nk , ik )的i的个数,再用( n+1 )减去这个个数就可以得到题上所求。
所以现在我们来想一想该怎么求这个个数:
首先我们知道n1,n2·····nk以及i1,i2·····ik都是小于p的,所以可以将所有的n以及i首尾相连想成两个p进制的数,所以只有C ( n1 , i1 ) C ( n2 , i2 ) .....C ( nk , ik ) 每一项都非0才满足条件,所以可以得到0<=i<=n,举个例子,C ( 11 , i )可以分解为C ( 2 , i1 ) , C ( 0 , i2 ) , C ( 1 , i3 ) , 所以i1有三种取法0,1,2,而i2有一种0 ,i3有两种0 ,1 ,所以一共要求的有3*2*1=6中,所以答案11+1-6=6 。总结一下就是 ( n+1 ) - ( n1+1 )( n2+1 ).....( nk+1 ).
代码如下:
#include<cstdio> #include<iostream> using namespace std; int tot; long long f[10001],n,p; int main(){ freopen("comb.in","r",stdin); freopen("comb.out","w",stdout); scanf("%I64d%I64d",&n,&p); long long k=n; while (k!=0){ f[++tot]=k%p; k/=p; } long long h=1; for (int i=1;i<=tot;i++) h*=(f[i]+1); printf("%I64d",(n+1)-h); return 0; }