首页 > 代码库 > 卡特兰数,高精度卡特兰数
卡特兰数,高精度卡特兰数
简介:卡特兰数是组合数学中经常出现的一个数列。
个人觉得无论是递推公式还是代表的含义都比斐波那契数列难理解一些。
递推公式:
应用:
1.Cn表示长度2n的dyck word的个数。Dyck word是一个有n个X和n个Y组成的字串,且所有的前缀字串皆满足X的个数大于等于Y的个数。以下为长度为6的dyck words
XXXYYY XYXXYY XYXYXY XXYYXY XXYXYY
分析:对于n个X,n个Y的排列来说一共有C(n,2n)种,还要排除其中不符合要求的排列。不符合条件的排列对于某个第2*m+1位,一定存在之前有m个X,m+1个Y,剩下的2n-2m-1位中有n-m个Y,n-m-1个X。对于所有m,它们的种类之和为C(n+1,2n),所以Cn=C(n,2n)-C(n+1,2n),即卡特兰数。
2.将上述X,Y换成左右括号询问正确匹配的括号数种类是同样的想法。
3.Cn表示在一个圆上有2n个点,用n条线把这2n个两两组成一队,并且每条线不能相交,问有多少种写法。
分析:将所有点编号为1~2n,对于1号点,如果它与2号点相连,那么1,2之间的连接方法为h(0),剩余点的连法为h(n-1)种,如果1号点和4号点相连,1,4之间的连接方法为h(1),剩余h(n-2)种,所以可以推得h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)。
具体题目:hdu 1134 http://acm.hdu.edu.cn/showproblem.php?pid=1134
4.用n个节点建立一棵二叉搜索树(每个节点的所有左子节点都小于本身,每个节点的所有右子节点都大于本身),能建立的种类数为h(n)种。
具体题目:hdu 1130 http://acm.hdu.edu.cn/showproblem.php?pid=1130
代码(高精度卡特兰数):
#include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <string.h> #include <ctime> #include <ctype.h> #include <iostream> #include <map> #include <queue> #include <set> #include <stack> #include <string> #include <vector> typedef long long LL; typedef unsigned long long ULL; using namespace std; const int ten[4]= {1,10,100,1000}; const int maxl = 300; struct BigNumber { int d[maxl]; char s[maxl]; BigNumber(const char s[]) { int len=strlen(s); d[0]=(len-1)/4+1; int i,j,k; for(int i=1; i<maxl; i++) d[i]=0; for(int i=len-1; i>=0; i--) { j=(len-i-1)/4+1; k=(len-i-1)%4; d[j]+=ten[k]*(s[i]-'0'); } while(d[0]>1&&d[d[0]]==0) d[0]--; } BigNumber() { *this=BigNumber("0"); } BigNumber(int x) { for (int i=0; i<maxl; i++) d[i]=0; if (!x) d[0]=1; while(x) { d[++d[0]]=x%10000; x/=10000; } } BigNumber(long long x) { for (int i=0; i<maxl; i++) d[i]=0; if (!x) d[0]=1; while(x) { d[++d[0]]=x%10000; x/=10000; } } void print() { int len=d[0]; printf("%d",d[d[0]]); for(int i=len-1; i>=1; i--) { if(d[i]>=1000) printf("%d",d[i]); else if(d[i]>=100) printf("0%d",d[i]); else if(d[i]>=10) printf("00%d",d[i]); else printf("000%d",d[i]); } printf("\n"); } void toString() { int top=0; int i,j,temp; for(i=3; i>=1; i--) if(d[d[0]]>=ten[i]) break; temp=d[d[0]]; for(j=i; j>=0; j--) { s[top++]=(char)(temp/ten[j]+'0'); temp%=ten[j]; } for(i=d[0]-1; i>0; i--) { temp=d[i]; for(j=3; j>=0; j--) { s[top++]=(char)(temp/ten[j]+'0'); temp%=ten[j]; } } } } zero=BigNumber(),d,temp,mid1[15],a[3005]; bool operator < (const BigNumber &a,const BigNumber &b) { if(a.d[0]!=b.d[0]) return a.d[0]<b.d[0]; int i; for(i=a.d[0]; i>0; i--) if(a.d[i]!=b.d[i]) return a.d[i]<b.d[i]; return false; } bool operator > (const BigNumber &a,const BigNumber &b) { if(b.d[0]!=a.d[0]) return b.d[0]<a.d[0]; int i; for(i=b.d[0]; i>0; i--) if(a.d[i]!=b.d[i]) return b.d[i]<a.d[i]; return false; } bool operator ==(const BigNumber &a,const BigNumber &b) { int i; if(a.d[0]!=b.d[0]) return false; for(i=1; i<=a.d[0]; i++) if(a.d[i]!=b.d[i]) return false; return true; } bool operator <= (const BigNumber &a,const BigNumber &b) { return a<b||a==b; } bool operator >= (const BigNumber &a,const BigNumber &b) { return a>b||a==b; } BigNumber operator +(const BigNumber &a,const BigNumber &b) { BigNumber c; c.d[0]=max(a.d[0],b.d[0]); int i,x=0; for(i=1; i<=c.d[0]; i++) { x=a.d[i]+b.d[i]+x; c.d[i]=x%10000; x/=10000; } while(x!=0) { c.d[++c.d[0]]=x%10000; x/=10000; } return c; } BigNumber operator -(const BigNumber &a,const BigNumber &b) { BigNumber c; c.d[0]=a.d[0]; int i,x=0; for(i=1; i<=c.d[0]; i++) { x=10000+a.d[i]-b.d[i]+x; c.d[i]=x%10000; x=x/10000-1; } while((c.d[0]>1)&&(c.d[c.d[0]]==0)) c.d[0]--; return c; } BigNumber operator *(const BigNumber &a,const BigNumber &b) { BigNumber c; c.d[0]=a.d[0]+b.d[0]; int i,j,x; for(i=1; i<=a.d[0]; i++) { x=0; for(int j=1; j<=b.d[0]; j++) { x=a.d[i]*b.d[j]+x+c.d[i+j-1]; c.d[i+j-1]=x%10000; x/=10000; } c.d[i+b.d[0]]=x; } while((c.d[0]>1)&&(c.d[c.d[0]]==0)) --c.d[0]; return c; } bool smaller(const BigNumber &a,const BigNumber &b,int delta) { if(a.d[0]+delta!=b.d[0]) return a.d[0]+delta<b.d[0]; int i; for(i=a.d[0]; i>0; i--) if(a.d[i]!=b.d[i+delta]) return a.d[i]<b.d[i+delta]; return true; } void Minus (BigNumber &a,const BigNumber &b,int delta) { int i,x=0; for(i=1; i<=a.d[0]-delta; i++) { x=10000+a.d[i+delta]-b.d[i]+x; a.d[i+delta]=x%10000; x=x/10000-1; } while((a.d[0]>1)&&(a.d[a.d[0]]==0)) a.d[0]--; } BigNumber operator *(const BigNumber &a,const int &k) { BigNumber c; c.d[0]=a.d[0]; int i,x=0; for(i=1; i<=a.d[0]; i++) { x=a.d[i]*k+x; c.d[i]=x%10000; x/=10000; } while(x>0) { c.d[++c.d[0]]=x%10000; x/=10000; } while((c.d[0]>1)&&(c.d[c.d[0]]==0)) c.d[0]--; return c; } BigNumber operator /(const BigNumber &a,const BigNumber &b) { BigNumber c; d=a; int i,j,temp; mid1[0]=b; for(int i=1; i<=13; i++) mid1[i]=mid1[i-1]*2; for(i=a.d[0]-b.d[0]; i>=0; i--) { temp=8192; for(j=13; j>=0; j--) { if(smaller(mid1[j],d,i)) { Minus(d,mid1[j],i); c.d[i+1]+=temp; } temp/=2; } } c.d[0]=max(1,a.d[0]-b.d[0]+1); while((c.d[0]>1)&&(c.d[c.d[0]]==0)) c.d[0]--; return c; } BigNumber operator %(const BigNumber &a,const BigNumber &b) { BigNumber c=a/b; return a-b*c; } BigNumber c[105]; void init() { c[0]=BigNumber(1); c[1]=BigNumber(1); for(int i=2;i<=100;i++) c[i]=c[i-1]*BigNumber(4*i-2)/BigNumber(i+1); } void solve() { int x; while(scanf("%d",&x)&&~x) { c[x].print(); } } int main() { init(); solve(); return 0; }