watashi的题解:
用dp[n][k]表示长度为2n深度不超过k的括号序列个数,那么答案就是dp[n][k]-dp[n][k-1]。
dp[i][j] = sum{dp[i-k][j] * dp[k-1][j-1] | 0<k≤i}
i对括号深度不超过j的,可以唯一表示为(X)Y形式,其中X和Y可以为空,设X有k-1对括号,则对应的方案数为dp[i-k][j] * dp[k-1][j-1]
需要用大数。
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <map> #include <algorithm> #define ll long long #define INF 2139062143 #define MOD 20071027 #define MAXN 100 using namespace std; struct BigNum { int len; char digit[MAXN]; BigNum() { strcpy(digit,"0"); len=1; } void set() { len=strlen(digit); } BigNum operator + (BigNum &p) { BigNum v; char c[MAXN]= {0}; int up=0,q=0; for(int i=len-1,j=p.len-1; i>=0||j>=0; --i,--j) { int x,y,z; if(i>=0) x=digit[i]-'0'; else x=0; if(j>=0) y=p.digit[j]-'0'; else y=0; z=x+y+up; c[q++]=z%10+'0'; up=z/10; } if(up)c[q++]='1'; c[q]=0; int &l=v.len; l=0; for(int i=q-1; i>=0; --i) v.digit[l++]=c[i]; if(l==0) v.digit[l++]='0'; v.digit[l]=0; return v; } BigNum operator - (BigNum &p) { BigNum v; char c[MAXN]; int down=0,q=0; for(int i=len-1,j=p.len-1; i>=0; --i,--j) { int x,y,z; x=digit[i]-'0'; if(j<0) y=0; else y=p.digit[j]-'0'; z=x-y+down; if(z<0) { down=-1; z+=10; } else down=0; c[q++]=z+'0'; } c[q]=0; int &l=v.len; l=0; bool ok=false; for(int i=q-1; i>=0; --i) { if(c[i]!='0') ok=true; if(ok) v.digit[l++]=c[i]; } v.digit[l]=0; return v; } BigNum operator * (BigNum &p) { BigNum v; int res[MAXN]= {0}; for(int i=len-1,I=0; i>=0; --i,++I) for(int j=p.len-1,J=0; j>=0; --j,++J) res[I+J]+=(digit[i]-'0')*(p.digit[j]-'0'); int L=len+p.len+1; for(int i=0; i<=L; ++i) { res[i+1]+=res[i]/10; res[i]=res[i]%10; } int &l=v.len; l=0; bool ok=false; for(int i=L; i>=0; --i) { if(res[i]) ok=true; if(ok) v.digit[l++]=res[i]+'0'; } if(!ok) v.digit[l++]='0'; v.digit[l]=0; return v; } }; BigNum dp[51][51]; void Init() { for(int i=0; i<=50; ++i) strcpy(dp[0][i].digit,"1"); for(int i=1; i<=50; ++i) for(int j=1; j<=50; ++j) for(int k=1; k<=i; ++k) dp[i][j]=dp[i-k][j]*dp[k-1][j-1]+dp[i][j]; } int main() { int n,k; Init(); int kase=0; while(scanf("%d%d",&n,&k)!=EOF) { if(!n&&!k) break; if(kase) printf("\n"); printf("Case %d: %s\n",++kase,(dp[n][k]-dp[n][k-1]).digit); } return 0; }