淺談求卡特蘭數的幾種方法
阿新 • • 發佈:2018-04-04
ade ++i return can 輸出 很好 include using 範圍
卡特蘭數是一個很常見的數列,以比利時的數學家歐仁·查理·卡塔蘭 (1814–1894)的名字來命名,其前幾項為 : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...(摘自百度百科)
卡特蘭數的求解方法
1.最基本的n^2遞推
例題:https://www.luogu.org/problemnew/show/P1044
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n; 5 int f[20]; 6 int main() 7 { 8 scanf("%d",&n); 9 f[0]=1; 10 f[1]=1,f[2]=2; 11 for(int i=3;i<=n;++i) 12 forView Code(int j=0;j<i;++j) 13 f[i]+=f[j]*f[i-j-1]; 14 cout<<f[n]<<endl; 15 return 0; 16 }
此題由於數據範圍非常小,既不會t也不會炸int,所以直接n^2求即可。證明不會qwq。
2.卡特蘭數的第n項h(n)=C(2n,n)-C(2n,n-1),所以用求組合數的方法求卡特蘭數即可,針對對一個大質數取模的代碼
1 #include<iostream> 2 #include<cstdio> 3View Codeusing namespace std; 4 int n,p; 5 int js[100005]; 6 int prime[100005]; 7 bool vis[100005]; 8 int cnt[100005]; 9 int qpow(int a,int b)//快速冪求逆元 10 { 11 int ans=1; 12 while(b) 13 { 14 if(b&1)ans=(1ll*a*ans)%p; 15 a=(1ll*a*a)%p; 16 b>>=1; 17 } 18 return ans; 19 } 20 int main() 21 { 22 scanf("%d%d",&n,&p);//求第n項,對p取模的結果,p為大質數 23 js[0]=1; 24 for(int i=1;i<=2*n;++i) 25 js[i]=(1ll*js[i-1]*i)%p; 26 int a=qpow(1ll*js[n]*js[n]%p,p-2),b=qpow(1ll*js[n-1]*js[n+1]%p,p-2); 27 a=1ll*a*js[2*n]%p,b=1ll*b*js[2*n]%p; 28 int ans=(a-b+p)%p;//a=C(2n,n)%p,b=C(2n,n-1)%p 29 printf("%d",ans); 30 return 0; 31 }
3.我們可以由第一種求法看出來卡特蘭數增長的是很快的,所以當要求的項數比較大而且不能取模時,需要用到高精,這時分解質因數求卡特蘭數就是一個很好的方法。
例題:https://www.luogu.org/problemnew/show/P2532
這題蒟蒻做的時候看到樣例輸入3,輸出5,直接想到卡特蘭數,沒想到是對的,233333333
代碼
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n; 5 int prime[1500],cnt; 6 bool vis[1550]; 7 int tong[1050]; 8 int ans[1100],len; 9 void cheng(int x,int sum)//高精乘低精 10 { 11 while(sum--) 12 { 13 for(int i=1;i<=len;++i)ans[i]*=x; 14 for(int i=1;i<=len;++i) 15 { 16 if(ans[i]>9) 17 { 18 ans[i+1]+=ans[i]/10,ans[i]%=10; 19 if(i+1>len)len++; 20 } 21 } 22 } 23 } 24 int main() 25 { 26 scanf("%d",&n); 27 vis[0]=vis[1]=1; 28 for(int i=2;i<=2*n;++i)//分解質因數 29 { 30 if(!vis[i])prime[++cnt]=i; 31 for(int j=1;j<=cnt&&prime[j]*i<=2*n;++j) 32 { 33 vis[i*prime[j]]=1; 34 if(i%prime[j]==0)break; 35 } 36 } 37 for(int i=1;i<=cnt;++i) 38 { 39 int tmp=2*n; 40 while(tmp/prime[i]>0)tong[i]+=tmp/prime[i],tmp/=prime[i]; 41 tmp=n;while(tmp/prime[i]>0)tong[i]-=tmp/prime[i],tmp/=prime[i]; 42 tmp=n+1;while(tmp/prime[i]>0)tong[i]-=tmp/prime[i],tmp/=prime[i]; 43 } 44 ans[1]=1,len=1; 45 for(int i=1;i<=cnt;++i) 46 { 47 if(tong[i]) 48 { 49 cheng(prime[i],tong[i]); 50 } 51 } 52 for(int i=len;i>=1;i--)printf("%d",ans[i]); 53 return 0; 54 }View Code
4.卡特蘭數的遞推公式h(n)=h(n-1)*(4*n-2)/(n+1),不過蒟蒻因為不是很懂,總是覺得沒譜,所以從來沒有用過這個遞推式。
淺談求卡特蘭數的幾種方法