lucas
作用:求C(n,m)(mod p){p∈Prime}
定理:设n=sp+q,m=tp+r,C(n,m)=C(sp+q,tp+r)=C(s,t)*C(q,r);
证明:
考虑组合数和二项式展开的系数的关系;
C(sp+q,tp+r)即为(1+x)^(sp+q)中x^(tp+r)项的系数;
展开(1+x)^(sp+q)
(1+x)^(sp+q)=((1+x)^p)^s*(1+x)^q;
(1+x)^p=∑C(p,i)x^i*1^(p-i)=∑C(p,i)x^i;当(0<i<p)时C(p,i)=p*(p-1)!/(i!*(p-i)!),在mod p的意义下,此式为0
所以(1+x)^p=C(p,0)*x^0+C(p,p)*x^p=(1+x^p);
所以(1+x)^sp+q=(1+x^p)^s*(1+x)^q=[∑C(s,i)x^(i*p)*1^(s-i)][∑C(q,j)x^j*1^(q-j)]=[∑C(s,i)x^(i*p)][∑C(q,j)x^j]
此时x^(i*p+j)的系数为C(s,i)*C(q,j),所以x^(tp+r)的系数为C(s,t)*C(q,r)
所以C(sp+q,tp+r)=C(s,t)*C(q,r);
模板题https://www.luogu.org/problemnew/show/P3807
#include<cstdio> #include<iostream> #include<ctype.h> #include<cmath> using namespace std; #define ll long long inline ll rd() { ll x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-') f=-f;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } inline ll ksm(ll x,ll n,ll mod){ll ans=1;for(;n;n>>=1,x=x*x%mod) if(n&1) ans=ans*x%mod;return ans;} inline ll C(int n,int m,int p) { if(n==m||!m) return 1;if(m>n) return 0;ll ans=1,g=1; for(int i=n-m+1;i<=n;i++) ans=ans*i%p; for(int i=1;i<=m;i++) g=g*i%p;return ksm(g,p-2,p)*ans%p; } inline ll lucas(int n,int m,int p) { if(n==m||!m) return 1;if(m>n) return 0; return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p; } int main() { for(int i=rd(),n,m,p;i;i--) n=rd(),m=rd(),p=rd(),printf("%lld ",lucas(n+m,m,p)); }
扩展lucas
作用:求C(n,m)(mod p)
{中国剩余定理是指对于一系列同余方程{x=a1(mod w1)……x=an(mod wn)},其中mi互质,一个合法解为{设W=Πwi,ti=(W/wi)在模wi意义下的逆元;ans=∑ai*ti*(W/wi);}
1:设p=Πbi^ci;
2:构造同余方程组wi=bi^ci,ai=C(n,m)(mod wi),设inv(x,y)表示x在模y意义下的逆元。
3:解同余方程组。
模板题:https://www.luogu.org/problemnew/show/P4720
#include<cstdio> #include<iostream> #include<ctype.h> #include<cmath> using namespace std; #define ll long long inline ll rd() { ll x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-') f=-f;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } ll exgcd(ll a,ll b,ll &x,ll &y) { if(!b){x=1;y=0;return a;} ll t=exgcd(b,a%b,x,y),w=x;x=y;y=w-a/b*x;return t; } ll inv(ll a,ll mod) { ll x,y,d=exgcd(a,mod,x,y); return d==1?(x%mod+mod)%mod:-1; } ll ksm(ll x,ll n,ll mod){ll ans=1;x%=mod;for(;n;n>>=1,x=x*x%mod)if(n&1)ans=ans*x%mod;return ans;} ll Mul(ll n,int p,int g) { if(n<2) return 1; ll ans=1; if(n/p) for(ll i=1;i<p;i++) if(i%g) ans=ans*i%p; ans=ksm(ans,n/p,p);for(ll i=n%p;i>1;i--) if(i%g) ans=ans*i%p;return ans*Mul(n/g,p,g)%p; } ll C(ll n,ll m,int g,int k,int mod) { if(m>n) return 0; ll a=Mul(n,k,g),b=Mul(m,k,g),c=Mul(n-m,k,g),i,w=0; for(i=n;i;i/=g) w+=i/g;for(i=m;i;i/=g) w-=i/g;for(i=n-m;i;i/=g)w-=i/g; ll ans=a*inv(b,k)%k*inv(c,k)%k*ksm(g,w,k)%k;ans=ans*(mod/k)%mod*inv(mod/k,k)%mod;return ans; } ll exlucas(ll n,ll m,int p) { ll ans=0,x=p; for(int i=2;i<=sqrt(x);i++) if(x%i==0) { int k=1; while(x>1&&x%i==0) x/=i,k*=i; ans=(ans+C(n,m,i,k,p))%p; } if(x>1) ans=(ans+C(n,m,x,x,p))%p; return ans; } int main() { ll n=rd(),m=rd(),p=rd(); printf("%lld",exlucas(n,m,p)); }