20201116 Day4 盧卡斯定理
阿新 • • 發佈:2020-11-16
Lucas 定理內容如下:對於質數 \(p\) ,有
\[\binom{n}{m}\bmod p = \binom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor}\cdot\binom{n\bmod p}{m\bmod p}\bmod p \]觀察上述表示式,可知 \(n\bmod p\) 和 \(m\bmod p\) 一定是小於 \(p\) 的數,可以直接求解, \(\displaystyle\binom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor}\)
時間複雜度為 \(O(f(p) + g(n)\log n)\) ,其中 \(f(n)\) 為預處理組合數的複雜度, \(g(n)\) 為單次求組合數的複雜度。
#include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <iostream> #include <queue> using namespace std; const int maxn=1e5+10; #define int long long int n,m,p,T; int a[maxn]; int pow(int y,int z,int p){ y%=p;int ans=1; for(int i=z;i;i>>=1,y=y*y%p) if(i&1) ans=ans*y%p; return ans; } int C(int n,int m){ if(m>n) return 0; return ((a[n]*pow(a[m],p-2,p))%p*pow(a[n-m],p-2,p)%p); } int Lucas(int n,int m){ if(!m) return 1; return C(n%p,m%p)*Lucas(n/p,m/p)%p; } int read(){ int a=0,op=1;char c=getchar(); while(c<'0'||c>'9') {if(c=='-') op=-1;c=getchar();} while(c>='0'&&c<='9') a*=10,a+=c^48,c=getchar(); return a*op; } #undef int int main(){ #define int long long T=read(); while(T--){ n=read(),m=read(),p=read(); a[0]=1; for(int i=1;i<=p;i++) a[i]=(a[i-1]*i)%p; printf("%lld\n",Lucas(m+n,n)); } return 0; }