组合数取模(Lucas)

原文地址



组合数取模在ACM竞赛中是一个很重要的问题,很多选手因为数据太大而束手无策,今天就来详细讲解它。

 

组合数取模就是求的值,当然根据的取值范围不同,采取的方法也不一样。

 

接下来,我们来学习一些常见的取值情况

 

(1)

 

     这个问题比较简单,组合数的计算可以靠杨辉三角,那么由于的范围小,直接两层循环即可。

 

(2),并且是素数

 

     这个问题有个叫做Lucas的定理,定理描述是,如果

 

     

 

     那么得到

 

     

   

     这样然后分别求,采用逆元计算即可。

 

 

题目:http://acm.fzu.edu.cn/problem.php?pid=2020

 

题意:,其中,并且是素数。

 

代码:

[cpp]  view plain  copy
 
  1. #include <iostream>  
  2. #include <string.h>  
  3. #include <stdio.h>  
  4.   
  5. using namespace std;  
  6. typedef long long LL;  
  7.   
  8. LL n,m,p;  
  9.   
  10. LL quick_mod(LL a, LL b)  
  11. {  
  12.     LL ans = 1;  
  13.     a %= p;  
  14.     while(b)  
  15.     {  
  16.         if(b & 1)  
  17.         {  
  18.             ans = ans * a % p;  
  19.             b--;  
  20.         }  
  21.         b >>= 1;  
  22.         a = a * a % p;  
  23.     }  
  24.     return ans;  
  25. }  
  26.   
  27. LL C(LL n, LL m)  
  28. {  
  29.     if(m > n) return 0;  
  30.     LL ans = 1;  
  31.     for(int i=1; i<=m; i++)  
  32.     {  
  33.         LL a = (n + i - m) % p;  
  34.         LL b = i % p;  
  35.         ans = ans * (a * quick_mod(b, p-2) % p) % p;  
  36.     }  
  37.     return ans;  
  38. }  
  39.   
  40. LL Lucas(LL n, LL m)  
  41. {  
  42.     if(m == 0) return 1;  
  43.     return C(n % p, m % p) * Lucas(n / p, m / p) % p;  
  44. }  
  45.   
  46. int main()  
  47. {  
  48.     int T;  
  49.     scanf("%d", &T);  
  50.     while(T--)  
  51.     {  
  52.         scanf("%I64d%I64d%I64d", &n, &m, &p);  
  53.         printf("%I64d\n", Lucas(n,m));  
  54.     }  
  55.     return 0;  
  56. }  


由于上题的比较大,所以组合数只能一个一个计算,如果的范围小点,那么就可以进行阶乘预处理计算了。

 


你可能感兴趣的:(组合数取模(Lucas))