您的位置:首页 > 其它

组合数相关的一些问题

2015-08-18 09:37 246 查看
组合数取模在ACM竞赛中是一个很重要也很常见的问题,之前碰到的很多时候都因为数据太大而束手无策,今天就来详细总结一下组合数相关的一些问题。

组合数取模就是求

的值,当然根据





的取值范围不同,采取的方法也是不一样。

接下来我们来看一些常见的取值情况:

(1)




对于这种情况,我们可以直接n2的求可以用组和数的递推公式c(n,m) =c(n - 1,m) + c(n – 1, m – 1)来计算,要么就用

组合数公式加逆元计算。

(2)



,并且

是素数

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



那么得到



这样分别计算就行啦(其实ni,mi相当于p进制下第i位的值)

(3)



,并且

可能为合数

因为

是合数,所以不能直接求逆元,那么可以先采取暴力分解,得到n!中素因子的指数,然后快速幂就行啦

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
typedef long long LL;
const int N = 200005;

bool prime
;
int p
;
int cnt;

void isprime(){
cnt = 0;
memset(prime,true,sizeof(prime));
for(int i=2; i<N; i++){
if(prime[i]){
p[cnt++] = i;
for(int j=i+i; j<N; j+=i)
prime[j] = false;
}
}
}

LL quick_mod(LL a,LL b,LL m){
LL ans = 1;
a %= m;
while(b){
if(b & 1)
ans = ans * a % m;
b >>= 1;
a = a * a % m;
}
return ans;
}

LL Work(LL n,LL p){
LL ans = 0;
while(n){
ans += n / p;
n /= p;
}
return ans;
}

LL Solve(LL n,LL m,LL P){
LL ans = 1;
for(int i=0; i<cnt && p[i]<=n; i++){
LL x = Work(n, p[i]);
LL y = Work(n - m, p[i]);
LL z = Work(m, p[i]);
x -= (y + z);
ans *= quick_mod(p[i],x,P);
ans %= P;
}
return ans;
}

int main(){
int T;
isprime();
cin>>T;
while(T--){
LL n,m,P;
cin>>n>>m>>P;
n += m - 2;
m--;
cout<<Solve(n,m,P)<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: