comb

Problem 3. comb
一天,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;
}
原文地址:https://www.cnblogs.com/ganster/p/8446742.html