Lucas定理學習筆記
阿新 • • 發佈:2018-12-20
Lucas定理:
此處的表示的是取模運算。
證明:
考慮化簡,不難發現當n和m都遠大於p的時候為了簡化運算我們可以將n,m,(n-m)都給按照p分段,如果,那麼可以發現以分數線為界,分數線上面的整數段一定和分數線下面的整數段相同,反之則分數線上面的整數段比下面的整數段大1(這種情況不難發現答案是0)。 於是我們只考慮上面和下面整數段相同的情況,先計算剩下來的邊角,根據同餘可得邊角料的部分為。 然後考慮對於這些整塊,要如何簡化運算。根據同餘定理和逆元的一些性質可以得到對於分子和分母對於p同餘且不是p的倍數的部分一定可以消掉,就像這樣: 然後我們把分子分母同時除以一個,就可以得到這部分的值為了。 最後可得。 證畢。 以上內容均為自己的對於Lucas定理及其證明的淺解,如有錯誤,歡迎指正。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define MREP(i,x) for(int i=beg[x],v;v=to[i],i;i=las[i])
#define debug(x) cout<<#x<<"="<<x<<endl
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;
using namespace std;
void File(){
freopen("luogu3807.in","r",stdin);
freopen("luogu3807.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=1e5+10;
int T;
ll n,m,p,fac[maxn<<1];
ll qpow(ll x,ll y){
ll ret=1; x%=p;
while(y){
if(y&1)ret=ret*x%p;
x=x*x%p;
y>>=1;
}
return ret;
}
ll calc(ll x,ll y){
if(x<p && y<p){
if(x<y)return 0;
return fac[x]*qpow(fac[y],p-2)%p*qpow(fac[x-y],p-2)%p;
}
return calc(x/p,y/p)*calc(x%p,y%p)%p;
}
int main(){
// File();
fac[0]=1;
read(T);
while(T--){
read(n),read(m),read(p);
REP(i,1,n+m)fac[i]=fac[i-1]*i%p;
printf("%lld\n",(calc(n+m,m)%p+p)%p);
}
return 0;
}