原来组合数取模是可以这样暴力的

来源:互联网 发布:淘宝标题组合工具箱 编辑:程序博客网 时间:2024/05/08 22:28
 

原来组合数取模是可以这样暴力的

分类: 数论 80人阅读 评论(0) 收藏 举报

题目:NEFU628 Garden visiting

 

对于组合数C(n,m),我们求C(n,m)%p,当然给定范围是0<=n,m<=10^6,p<=10^5注意这里p不一定是素数,如果p是素数,很明显,Lucas一下搞定毫

无压力,但是p可能为合数。。。。。。。

对于这个我参照了AC大牛的思路,我们先求出阶乘中各个素因子的幂的次数,这里很巧妙,对于分母的话,就是负次幂,然后直接把每个素因子的幂

统计在一个数组里面保存,最后就直接二分求问题的解,具体思路参照代码:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. typedef long long LL;  
  5.   
  6. const int N = 2000001;  
  7. const int M = 150000;  
  8.   
  9. LL MOD;  
  10.   
  11. bool prime[N];  
  12. LL   p[M];  
  13. LL   k=0;  
  14.   
  15. void isprime()  
  16. {  
  17.     LL i,j;  
  18.     memset(prime,true,sizeof(prime));  
  19.     for(i=2;i<N;i++)  
  20.     {  
  21.         if(prime[i])  
  22.         {  
  23.             p[k++]=i;  
  24.             for(j=i+i;j<N;j+=i)  
  25.             {  
  26.                 prime[j]=false;  
  27.             }  
  28.         }  
  29.     }  
  30. }  
  31.   
  32. LL multi(LL a, LL b, LL m)  
  33. {  
  34.     LL ans=0;  
  35.     a%=m;  
  36.     while(b)  
  37.     {  
  38.         if(b&1)  
  39.         {  
  40.             ans=(ans+a)%m;  
  41.             b--;  
  42.         }  
  43.         b>>=1;  
  44.         a=(a+a)%m;  
  45.     }  
  46.     return ans;  
  47. }  
  48.   
  49. LL quick_mod(LL a,LL b,LL m)  
  50. {  
  51.     LL ans=1;  
  52.     a%=m;  
  53.     while(b)  
  54.     {  
  55.         if(b&1)  
  56.         {  
  57.             ans=ans*a%m;  
  58.             b--;  
  59.         }  
  60.         b>>=1;  
  61.         a=a*a%m;  
  62.     }  
  63.     return ans;  
  64. }  
  65.   
  66. LL fac(LL n,LL A[],LL d)  
  67. {  
  68.     LL i;  
  69.     for(i=0;i<k&&p[i]<=n;i++)  
  70.     {  
  71.         LL x=n;  
  72.         while(x)  
  73.         {  
  74.             A[i]+=d*(x/p[i]);  
  75.             x/=p[i];  
  76.         }  
  77.     }  
  78.     return i;  
  79. }  
  80.   
  81. LL C(LL n,LL m)  
  82. {  
  83.     LL temp;  
  84.     LL A[M];  
  85.     memset(A,0,sizeof(A));  
  86.     temp=fac(n,A,1);  
  87.     fac(m,A,-1);  
  88.     fac(n-m,A,-1);  
  89.     LL ret=1;  
  90.     for(LL i=0;i<temp;i++)  
  91.         ret=multi(ret,quick_mod(p[i],A[i],MOD),MOD);  
  92.     return ret%MOD;  
  93. }  
  94.   
  95. int main()  
  96. {  
  97.     isprime();  
  98.     LL t,n,m;  
  99.     scanf("%I64d",&t);  
  100.     while(t--)  
  101.     {  
  102.         scanf("%I64d%I64d%I64d",&n,&m,&MOD);  
  103.         LL ans = C(m+n-2,n-1)%MOD;  
  104.         printf("%I64d\n",ans);  
  105.     }  
  106.     return 0;  
  107. }  
原创粉丝点击