题目描述:
定义一个括号序列的Depth为最深的嵌套层数。问n对括号,depth为k的括号序列共有多少种。
分析:
很类似Catalan数的题目。回忆经典的Catalan数:f[n]表示n对括号能够组成多少种不同的序列。那么可以得出f[n]的递推式:
f[n]=∑f[i]*f[n-i-1](0<=i<n)
对于此题可以用类似的思路得到递推式。
设f[i][j]表示i对括号能组成多少个depth为j的的序列。那么初始条件为f[0][0]=f[1][1]=1。考虑f[i][j],设与第一个前括号配对的后括号之间有k对括号(如下图),那么可以把f[i][j]分为两个子问题:括号里的k对括号,和括号后面的i-k-1对括号。
( ..[k对括号].. ) ..[i-k-1对括号]..
那么可以写出以下递推式:
f[i][j] = ∑ ( f[k][j-1]*g[i-k-1][j-1] + g[k][j-1]*f[i-k-1][j] ) ,(0<=k<i),其中g[i][j]=∑f[i][k](0<=k<=j)。
显然最后数字很大,需要大数。
- /*
- ZJU2604 Little Brackets
- */
- #include <stdio.h>
- #include <string.h>
- #define clr(a) memset(a,0,sizeof(a))
- #define cpy(a,b) memcpy(a,b,sizeof(b))
- #define N 51
- /****************************************************/
- #define DIGIT 4 //一个数组元素存放的位数个数
- #define DEPTH 10000 //DEPTH = 10DIGIT
- #define MAX 500 //数组的长度
- typedef int bignum_t[MAX+1];
- //赋值
- void value(bignum_t a,const char val[]){ //val为数字字符串
- char buf[MAX*DIGIT+1],ch;
- int i,j;
- memset((void*)a,0,sizeof(bignum_t));
- memcpy(buf,val,sizeof(val));
- for (a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
- ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch;
- for (a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
- for (i=1;i<=a[0];i++)
- for (a[i]=0,j=0;j<DIGIT;j++)
- a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0';
- for (;!a[a[0]]&&a[0]>1;a[0]--);
- }
- //输出
- void Write(const bignum_t a){
- int i,j;
- for (printf("%d",a[i=a[0]]),i--;i;i--)
- for (j=DEPTH/10;j;j/=10)
- printf("%d",a[i]/j%10);
- puts("");
- }
- //加法
- void add(bignum_t a,const bignum_t b){//高精度数a+b,结果在a中
- int i;
- for (i=1;i<=b[0];i++)
- if ((a[i]+=b[i])>=DEPTH) a[i]-=DEPTH,a[i+1]++;
- if (b[0]>=a[0]) a[0]=b[0];
- else
- for (;a[i]>=DEPTH&&i<a[0];a[i]-=DEPTH,i++,a[i]++);
- a[0]+=(a[a[0]+1]>0);
- }
- //大数乘大数
- void mul(bignum_t c,const bignum_t a,const bignum_t b){//高精度数a*b,结果在c中
- int i,j;
- memset((void*)c,0,sizeof(bignum_t));
- for (c[0]=a[0]+b[0]-1,i=1;i<=a[0];i++)
- for (j=1;j<=b[0];j++)
- if ((c[i+j-1]+=a[i]*b[j])>=DEPTH)
- c[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH;
- for (c[0]+=(c[c[0]+1]>0);!c[c[0]]&&c[0]>1;c[0]--);
- }
- /**************************************************/
- bignum_t f[N][N];
- bignum_t g[N][N];
- bignum_t x,y;
- #define G(a,b) ((a)<(b)?(g[a][a]):(g[a][b]))
- int main()
- {
- int i,j,k,n,m,T=0;
- for(i=0;i<N;i++) for(j=0;j<N;j++){
- value(f[i][j],"0"); value(g[i][j],"0");
- }
- //DP
- value(f[0][0],"1"); value(f[1][1],"1");
- value(g[0][0],"1"); value(g[1][1],"1");
- for(i=2;i<N;i++) for(j=1;j<=i;j++){
- for(k=0;k<i;k++){
- mul(x,f[k][j-1],G(i-k-1,j-1));
- mul(y,G(k,j-1),f[i-k-1][j]);
- add(x,y);
- add(f[i][j],x);
- }
- cpy(g[i][j],g[i][j-1]);
- add(g[i][j],f[i][j]);
- }
- //input
- while(scanf("%d%d",&n,&m),n+m){
- if(T) puts("");
- printf("Case %d: ",++T);
- Write(f[n][m]);
- }
- return 0;
- }