首页 > 代码库 > 组合数总结

组合数总结

                                  痛定思痛

 

  由于前期没有认真的考虑学过的算法的使用限制,造成了区域赛的夺银擦肩。于是,我决定没一个我学习过的算法都认真总结,分析。

组合数的求解一般有三种:

一、杨辉三角法

二、Lucas暴力求解

三、Lucas打表法

 

第一种就这里就略过。

第二种

给出的C(N,M) % P ,这时候的N,P都很大,没发打表。而M相对来说比较小。所以,此时我们可以运用暴力的求解方法。这里的数据范围一般是(N < 10^18,P < 10^9),M < 10^5 (P要为素数)

经典题目链接

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

typedef long long LL;

LL N,M,P;

LL powmod(LL a,LL b,LL p){
   LL res = 1;
   a %= p;

   while(b > 0){
       if(b & 1) res = res * a % p;
       a = a * a % p;
       b >>= 1;
   }

   return res;
}

//暴力循环求解
LL Norma_C(LL n,LL m,LL p){
    LL ans = 1;
    for(int i = 1;i <= m;++i){
        LL a = (n + i - m) % p;
        LL b = i % p;
        ans = ans * (a * powmod(b,p-2,p) % p) % p;
    }
    return ans;
}

LL Lucas(LL n,LL m,LL p){
    if(!m) return 1;
    if(n%p < m%p) return 0;
    LL tmp = Norma_C(n%p,m%p,p);
    return tmp * Lucas(n / p,m / p,p);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%I64d%I64d%I64d",&N,&M,&P);
        printf("%I64d\n",Lucas(N,M,P));
    }
    return 0;
}



 

 

 

 

 

 

 

 

 

 

组合数总结