用d[i][j][u][v]表示i个{},j个[],u个(),深度为v的序列数,根据最后一个子括号(就是最后一个反括号对应的正括号范围内的括号)分类计数。
最后一个子括号可能深度小于v,此时前面的括号深度必须为v,最后一个子括号深度也可能等于v,此时前面的括号深度可以小于或等于v。
用sum[i][j][u][v]表示i个{},j个[],u个(),深度小于等于v的序列数。没递推完i,j,u后,立即计算相应的sum[i][j][u][0…D]的值。
枚举最后一个子括号内有哪些括号完成递推。
#include<stdio.h>
#include<stdlib.h>
int d[12][12][12][32];
int sum[12][12][12][32];
int main(void)
{
int i,j,u,v,p,q,n,m,vi,vj,vu,sump;
scanf("%d%d%d%d",&q,&n,&m,&p);
d[0][0][0][0]=1;
sum[0][0][0][0]=1;
for(i=0;i<=q;i++)
{
for(j=0;j<=n;j++)
{
for(u=0;u<=m;u++)
{
for(v=1;v<=p;v++)
{
if(i+j+u<v)
{
d[i][j][u][v]=0;
}
else
{
if(i!=0)
{
sump=d[i-1][j][u][v-1];
}
else if(j!=0)
{
sump=d[0][j-1][u][v-1];
}
else if(u!=0)
{
sump=d[0][0][u-1][v-1];
}
else
{
sump=0;
}
for(vi=0;vi<=i;vi++)
{
for(vj=0;vj<=j;vj++)
{
for(vu=0;vu<=u;vu++)
{
if((vi+vj+vu!=0)&&(vi+vj+vu!=i+j+u))
{
if(vi!=0)
{
if(v>=2)
{
sump=(sump+sum[vi-1][vj][vu][v-2]*d[i-vi][j-vj][u-vu][v])%11380;
}
sump=(sump+d[vi-1][vj][vu][v-1]*sum[i-vi][j-vj][u-vu][v])%11380;
}
else if(vj!=0)
{
if(v>=2)
{
sump=(sump+sum[0][vj-1][vu][v-2]*d[i][j-vj][u-vu][v])%11380;
}
sump=(sump+d[0][vj-1][vu][v-1]*sum[i][j-vj][u-vu][v])%11380;
}
else
{
if(v>=2)
{
sump=(sump+sum[0][0][vu-1][v-2]*d[i][j][u-vu][v])%11380;
}
sump=(sump+d[0][0][vu-1][v-1]*sum[i][j][u-vu][v])%11380;
}
}
}
}
}
d[i][j][u][v]=sump;
}
}
for(v=1;v<=p;v++)
{
sum[i][j][u][v]=(sum[i][j][u][v-1]+d[i][j][u][v])%11380;
}
}
}
}
printf("%d\n",d[q][n][m][p]);
return 0;
}