【描述】
公元19881231年,一颗巨大的陨石坠落在世界的政治文化中心cs。于是,灾难降临了,地球上出现了一系列反常的现象。当人们焦急万分的时候,一支由cs科学家组成的考察队赶到了出事地点。经过一番侦察,科学家们发现陨石上刻有若干行密文,每一行都包含5个整数:
1 1 1 1 6
0 0 6 3 57
8 0 11 3 2845
著名的科学家yh发现,这些密文实际上是一种复杂运算的结果。为了便于大家理解这种运算,他定义了一种yh表达式:
1. yh表达式是仅由'{','}','[',']','(',')'组成的字符串。
2. 一个空串是yh表达式。
3. 如果A是yh表达式,且A中不含字符'{','}','[',']',则(A)是yh表达式。
4. 如果A是yh表达式,且A中不含字符'{','}',则[A]是yh表达式。
5. 如果A是yh表达式,则{A}是yh表达式。
6. 如果A和B都是yh表达式,则AB也是yh表达式。
例如 ()(())[] , {()[()]}, { {[[(())]]}} 都是yh表达式。
而 ()([])() , [() 都不是SS表达式。
并且,我们定义,该串总的括号最大层数为该串的深度,例如(){()}[]的深度为2。
密文中的复杂运算是这样进行的:
设密文中每行前4个数依次为L1,L2,L3,D,求出所有深度为D,含有L1对{},L2对[],L3对()的SS串的个数,并用这个数对数11380求余数,这个余数就是密文中每行的第5个数,我们称之为神秘数。
密文中某些行的第五个数已经模糊不清,而这些数字正是揭开陨石秘密的钥匙。现在科学家们聘请你来计算这个神秘数。
【输入格式】
共一行,4个整数L1,L2,L3,D。相邻两个数之间用一个空格分隔。
【输出格式】
共一行,包含一个整数,即神秘数
【样例输入】
1 1 1 2
【样例输出】
8
【数据范围】
L1,L2,L3<=10,D<=30。
【分析】
恩,很明白,不会……
然后搜题解,找到了BYD大牛。
于是看了题解,于是会了。囧。
以下引用BYD大牛的题解:
“容易看出是动态规划,但是状态转移方程容易考虑不周全。
题目中样例的8种方案为
{[]()} {()[]} {}[()] [()]{} []{()} {()}[] (){[]} {[]}()
可以看出每个SS表达式都可以看成由几个小的SS组成,组成方式可能是嵌套或者连接。如果是嵌套(包括仅1层),我们把这个嵌套体看作一个整体部分,称为一个组。则每个SS表达式都是由几个组连接而成了。
设定 F[p1,p2,p3,d]为深度不超过d,包含p1个{},p2个[],p3个()的SS表达式的可能组成的方案数。S[p1,p2,p3,d]为深度不超过d,包含p1个{},p2个[],p3个()的一个组的可能组成的方案数。
则状态转移方程为
S[p1,p2,p3,d]={0 (p1==p2==p3==0)F[p1-1,p2,p3,d-1] (p1>=1)F[p1,p2-1,p3,d-1] (p1==0 && p2>=1)F[p1,p2,p3-1,d-1] (p1==0 && p2==0 && p3>=1)}
F[p1,p2,p3,d]=Σ(S[x1,x2,x3,d]*F[p1-x1,p2-x2,p3-x3,d]) (0<=x1<=p1,0<=x2<=p2,0<=x3<=p3且x1,x2,x3不同时为0)
初始条件
- F[0,0,0,i]=1 (0<=i<=D)
最终的结果就是
- F[L1,L2,L3,D]-F[L1,L2,L3,D-1]”
#include
#define maxn 35int f[maxn][maxn][maxn][maxn];
int l1,l2,l3,d,ans,base=11380;
int dp(int p1,int p2,int p3,int d);int s(int p1,int p2,int p3,int d)
{if (p1) return dp(p1-1,p2,p3,d-1);if (p2) return dp(p1,p2-1,p3,d-1);return dp(p1,p2,p3-1,d-1);
}int dp(int p1,int p2,int p3,int d)
{if (d<0) return 0;if (f[p1][p2][p3][d]==-1){f[p1][p2][p3][d]=0;for (int x1=0;x1<=p1;++x1)for (int x2=0;x2<=p2;++x2)for (int x3=0;x3<=p3;++x3){if (x1+x2+x3==0) continue;f[p1][p2][p3][d]+=(s(x1,x2,x3,d)*dp(p1-x1,p2-x2,p3-x3,d))%base;f[p1][p2][p3][d]%=base;}}return f[p1][p2][p3][d];
}int main()
{freopen("secret.in","r",stdin);freopen("secret.out","w",stdout);scanf("%d%d%d%d",&l1,&l2,&l3,&d);for (int i=0;i<=d;++i){for (int p1=0;p1<=l1;++p1)for (int p2=0;p2<=l2;++p2)for (int p3=0;p3<=l3;++p3)f[p1][p2][p3][i]=-1;f[0][0][0][i]=1;}ans=dp(l1,l2,l3,d)-dp(l1,l2,l3,d-1);ans=(ans+base)%base;printf("%d
",ans);return 0;
}