yimao哥的求组合数取余的模板,涨姿势了(¯﹃¯)
/*
组合数的计算;
C(n,m)= n*(n-1)*...*(n-m+1) / m!;
注意到本题,m最大为10^4,1s的时限(保守估计是10^7),所以直接计算不超时;
分子: fz: 表示分子:fz= n*(n-1)*...*(n-m+1);最多10^4次乘法,
边乘要边取模;
分母: fm: 表示分母:fm= m*(m-1)*...*2*1;最多10^4次乘法,
边乘要边去模;
最后分母要求对模数p的逆元再与分子相乘;
*/
#include <cstdio>
#include <iostream>
using namespace std;
int ext_gcd(int a, int b, int &x, int &y){
if( !b ) return x=1,y=0,a;
int d= ext_gcd(b, a%b, y, x);
y-= a/b*x;
return d;
}
int Inv(int a, int m){
int d,x,y;
d= ext_gcd(a,m,x,y);
return (x%m+m)%m;
}
/*计算组合数C(n,m)%p,其中m<=10^4,p是素数,且m<p;
fm: 表示分母:fm= m*(m-1)*...*2*1;
fz: 表示分子:fz= n*(n-1)*...*(n-m+1);
取余对除法不具有封闭性,
必须求出除数(即分母)对模数p的逆元,转换成乘法;
C(n,m)= n*(n-1)*...*(n-m+1) / m!;
C(n,m)%p = (fz%p) * Inv( (fm%p), p ) %p;
*/
long long Comb(int n, int m, int p){
long long fm=1, fz= 1;
for(int i=2; i<=m; ++i)
fm= fm*i%p;
for(int i=n-m+1; i<=n; ++i)
fz= fz*i%p;
long long ret= fz * Inv( fm, p ) %p;
return ret<0 ? ret+p : ret;
}
int main()
{
//freopen("E.in","r",stdin);
int T,n,m,p;
cin>>T;
while( T-- ){
cin>>n>>m>>p;
cout<< Comb( n, m, p ) <<endl;
}
}