1. 程式人生 > >學習盧卡斯定理一篇QWQ

學習盧卡斯定理一篇QWQ

首先,我們得知道盧卡斯定理求得是啥。。。

比如C(n,m)求的是從n個數中取m個數的組合數

而C(n,m)等於的是n!/(m!*!(n-m))。。不否認我們可以遞推過去。。但是如果如果 m很大呢。。。大的達到了一個天文數字級別。。你該怎麼辦呢。。好吧盧卡斯也沒有辦法。。

但是,但是,如果MOD上一個素數P,結果就會很小,有人會說,我直接一邊乘一邊mod唄。。不是一樣嗎。。 我相信盧卡斯不會閒著沒事幹幹這種事的,,,瞎掰個定理來玩你。。。

試想若果你乘的階乘裡面有一個modP等於0的數呢。。sisisisis。。不太好,不太好。。。 可是我們的這個n!/(m!*!(n-m))除後得到的結果是不會是P的倍數的(一般);

所以下面就正式來講lucas(n+m,m)這個蛇皮的東西

首先lucas既然是為了將天文數字降下來。。。那麼我們的初始化。要初始化多少捏。。。

準確的說是1!------P!,都要用到。。原因是程式碼中會講;

第一段 初始化 本人手懶就std關庫cin了

std::ios::sync_with_stdio(false);
	cin>>T;
	while(T--){
		cin>>n>>m>>p; fac[0]=1; 
		for(int i=1; i<=p; ++i) fac[i]=fac[i-1]*i%p; 
		cout<<
lucas(n+m,m)%p<<endl;

你問為神馬是n+m,m嗎 額 你問你谷zcy這位管理員去,這個鍋我不背 你谷盧卡斯定理模板

下面我們就簡化成n和m即n=原來的n+m,m也就顯而易見了

lucas定理主要證明就是(x) 我不會

他們都貼的是馮志剛的37頁初等數論。。可惜我數競太差了,,看不懂。。

所以友善的貼一下另一位大佬的證明部落格 記得回來呀

所以我們得出 lucas(n,m)=lucas(n/P,m/P)*C(n%P,m%P) 的一條公式

誒你說和你之前看的不一樣,,額,那種寫法被我拋棄了。。 簡單貼一下那種程式碼

#include<bits/stdc++.h>
using namespace std; typedef long long ll; const int MAXN=1e5,N=1e5+10; ll p,a[N],b[N]; ll Lucas(ll x,ll y) { if (x<y) return 0; if (x<p&&y<p) return a[x]*b[x-y]%p*b[y]%p; return Lucas(x%p,y%p)*Lucas(x/p,y/p)%p; } int main() { int T; scanf("%d",&T); while (T--) { ll n,m; scanf("%lld%lld%lld",&n,&m,&p); n+=m; a[0]=1; for (register ll i=1; i<=p-1; ++i) a[i]=a[i-1]*i%p; b[1]=1; for (register ll i=2; i<=p-1; ++i) b[i]=((-p/i*b[p%i])%p+p)%p; b[0]=1; for (register ll i=1; i<=p-1; ++i) b[i]=b[i]*b[i-1]%p; printf("%lld\n",Lucas(n,m)); } return 0; }

不知道為什麼之前的註釋會亂碼,,不放上去了。。

然後我們會驚奇的發現C(n%P,m%P)我們是能求的

這裡要用到逆元的知識,本人不在普及,,

即C下n!/(m!*(n-m)!) n!,m!,(n-m)!我們都求出來了?????為啥

我們看看前面的

首先lucas既然是為了將天文數字降下來。。。那麼我們的初始化。要初始化多少捏。。。 準確的說是1!------P!,都要用到。。原因是程式碼中會講;

終於用到了,,呵呵。。都%過了,還怕比他大?

所以一切結束

貼程式碼

#include<bits/stdc++.h>
using namespace std;
long long n,m,p,T,fac[100010];
long long fpow(int x,int y){
    long long res=x; y--;
    while(y){if (y&1) res=1ll*res*x%p; 
    x=1ll*x*x%p; y/=2;  }return res; 
}
long long C(int n,int m){
    if (m>n) return 0; 
    return (fac[n]*fpow((fac[m]*fac[n-m])%p,p-2)%p);
}
long long lucas(int n,int m){
    if (m==0) return 1; 
    return (lucas(n/p,m/p)*C(n%p,m%p))%p;}
int main(){
    std::ios::sync_with_stdio(false);
    cin>>T;
    while(T--){
        cin>>n>>m>>p; fac[0]=1; 
        for(int i=1; i<=p; ++i) fac[i]=fac[i-1]*i%p; 
        cout<<lucas(n+m,m)%p<<endl;
    }
}

程式碼略醜,大佬勿噴。。。

																		THE END