洛谷P3807盧卡斯定理
阿新 • • 發佈:2019-01-13
這是一道模板題
這裡是題目 洛谷P3807
盧卡斯定理及題目的闡釋
盧卡斯定理是用來解決一大很大的組合數來和一個質數求餘的問題,它的定義如下
如果p為素數,設n=sp+q,m=tp+r
則:
那麼來看看題。
首先看這個資料範圍,就知道可以用int的型別解決個屁,就是int害的我錯了好多次long long 的資料型別解決,這個資料看起來好像是隻有 10的5次方,但是中間這麼多的計算,突然的就給我溢位了我靠著ZFN大佬的資料測試發現負數才發現的。
long long C(int n,int m,int p){ if(n<m)return 0; if(n==m)return 1; if(m>n-m)m=n-m;//約掉 long long s1=1,s2=1; for(int i=0;i<m;i++){ s1=s1*(n-i)%p; s2=s2*(i+1)%p; } return s1*qkpow(s2,p-2,p)%p; }
這一段是求組合的函式,拿出來單獨講一講
因為這裡面的引數傳過來的時候都是已經和p求過餘了的,而且p在題目中說了的,是一個質數所以說這裡的n,m都是和p互質的。
因為公式裡面要除掉m!
,同時有要去對p取模,所以考慮用它的逆元乘來代替用它來除
而根據費馬小定理可以知道它的逆元是它的p-2
方
程式碼
那麼綜上,加上以個快速冪就可以解出這道題了
//洛谷P3807 Lucas 模板題 #include<bits/stdc++.h> #define maxn 100005 using namespace std; int n,m,p; long long qkpow(long long b,int p,int mod){ long long res=1; while(p){ if(p&1){ (res*=b)%=mod; } (b*=b)%=mod; p>>=1; } return res; } long long C(int n,int m,int p){ if(n<m)return 0; if(n==m)return 1; if(m>n-m)m=n-m;//約掉 long long s1=1,s2=1; for(int i=0;i<m;i++){ s1=s1*(n-i)%p; s2=s2*(i+1)%p; } return s1*qkpow(s2,p-2,p)%p; } long long Lucas(int n,int m,int p){ if(m==0)return 1; return C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p; } int main(){ #ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif int t; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&p); n+=m; cout<<Lucas(n,m,p)<<"\n"; } return 0; }