1. 程式人生 > >淺談求卡特蘭數的幾種方法

淺談求卡特蘭數的幾種方法

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         for
(int j=0;j<i;++j) 13 f[i]+=f[j]*f[i-j-1]; 14 cout<<f[n]<<endl; 15 return 0; 16 }
View Code

此題由於數據範圍非常小,既不會t也不會炸int,所以直接n^2求即可。證明不會qwq。

2.卡特蘭數的第n項h(n)=C(2n,n)-C(2n,n-1),所以用求組合數的方法求卡特蘭數即可,針對對一個大質數取模的代碼

技術分享圖片
 1 #include<iostream>
 2 #include<cstdio> 
 3
using 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 }
View Code

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),不過蒟蒻因為不是很懂,總是覺得沒譜,所以從來沒有用過這個遞推式。

淺談求卡特蘭數的幾種方法