点击查看折叠代码块
/*
C(n,m) % p = n!/(m! * (n-m)!) % p = n! % p * inv[m!] % p * inv[(n-m)!] % p
求出1-n的前缀积pre[1]--pre[n] 和 1-n的逆元的前缀积 pre_inv[1]--pre_inv[n]
则 C(n,m) = pre[n] % p * pre_inv[m] % p * pre_inv[n-m] % p
卢卡斯定理:
Lucas(n,0) = 1
Lucas(n,m) % p = Lucas(n/p,m/p) * C(n % p,m % p)
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
ll n,m,Mod;
int T;
ll mypow(ll a,ll b){
ll inv = 1;
while( b ){
if( b&1 ) inv = inv*a%Mod;
a = a*a%Mod;
b >>= 1;
}
return inv;
}
ll inv[maxn];//逆元
ll pre[maxn],pre_inv[maxn];
void init(ll n){//线性求逆元
inv[0]=inv[1]=1;
for (int i=2;i<=n;i++){
inv[i] = ((Mod-Mod/i) *inv[Mod % i]) % Mod;
}
}
void init_pre(ll n){//求出1-n的前缀积和逆元前缀积
pre[0] = pre_inv[0] = 1;
for (int i=1;i<=n;i++){
pre[i] = pre[i-1] * i % Mod;
pre_inv[i] = pre_inv[i-1] * inv[i] % Mod;
}
}
ll C(ll n,ll m){
if(m>n) return 0;
return pre[n] * pre_inv[m] % Mod * pre_inv[n-m] % Mod;//记得取模
}
ll Lucas(ll n,ll m){
if(m==0) return 1;
return Lucas(n/Mod,m/Mod) * C(n % Mod,m % Mod) % Mod;//记得取模
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%lld%lld%lld",&n,&m,&Mod);
init(n+m);
init_pre(n+m);
printf("%lld\n",Lucas(n+m,n));
}
return 0;
}