Lucas定理
Lucas定理
适用于大组合数取模。
C(n,m)%p==lucas(n,m,p)==C(n%p,m%p)*lucas(n/p,m/p,p);然后递归调用即可,显然,C(n,0)%p=1;
因为p是质数,这里套用费马小定理,a^(p-1)=1(mod p),a的逆元为a^(p-2),然后套快速幂,预处理阶乘。
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<cmath> #include<ctime> #include<cstring> #define inf 2147483647 #define For(i,a,b) for(register long long i=a;i<=b;i++) #define p(a) putchar(a) #define g() getchar() //by war //2017.10.15 using namespace std; long long n,m,p,t; long long a[1000010]; void in(long long &x) { long long y=1; char c=g();x=0; while(c<'0'||c>'9') { if(c=='-') y=-1; c=g(); } while(c<='9'&&c>='0')x=x*10+c-'0',c=g(); x*=y; } void o(long long x) { if(x<0) { p('-'); x=-x; } if(x>9)o(x/10); p(x%10+'0'); } long long ksm(long long a,long long b,long long p) { while(b%2==0) { a*=a; a%=p; b>>=1; } long long r=1; while(b>0) { if(b%2==1) { r*=a; r%=p; } a*=a; a%=p; b>>=1; } return r%p; } long long c(long long n,long long m,long long p) { if(m>n) return 0; return (a[n]%p)*ksm(a[n-m]*a[m],p-2,p)%p; } long long lucas(long long n,long long m,long long p) { if(!m) return 1; return (c(n%p,m%p,p)%p)*lucas(n/p,m/p,p)%p; } int main() { in(t); while(t--) { in(n),in(m),in(p); a[0]=1; For(i,1,(n+m+1)) a[i]=(a[i-1]*i)%p; o(lucas(n+m,m,p)),p('\n'); } return 0; }