圆括号

来源:互联网 发布:understand mac 破解 编辑:程序博客网 时间:2024/06/15 22:04

圆括号

题目描述

慧音正在教妹红什么是合法括号序列:
空字符串是一个合法括号序列。
如果XY都是合法括号序列,那么XY(即字符串Y拼在字符串X的后面所组成的新的字符串)是一个合法括号序列。
如果X是合法括号序列,那么 (X)也是合法括号序列(即在X的左边加一个左括号,右边加一个右括号)
所有的合法括号序列都可以用~的规则所构造出来。
现在妹红得到了两个括号序列(注意,不一定合法),记为XY,她想构造出一个新的括号序列Z。她每一次会将XY的最左边的字符加进Z的末尾,然后将其从XY中删去,直到XY都为空。她问慧音有多少种选择方案可以让Z是一个合法括号序列。两种选择方案不同是指至少存在一个位置k,使得第一种方案中Z的第k位从X得来,而在第二种方案中Z的第k位从Y得来(不是指两种方案的Z不同)。方案数mod 1000000007(10^9+7)
妹红觉得很好玩,于是她决定再随机生成偶数个括号序列,向慧音多次询问(即多组测试数据)。然而慧音并不知道怎么做,于是她交给了学OI的你。

输入格式 1989.in

第一行一个整数T,表示询问组数。
接下来每组询问有两行,每行一个字符串,分别代表题目中的XY

输出格式 1989.out

T行,每行一个整数,代表生成合法括号序列的方案数。

输入样例 1989.in

6
(()
())
(
)
(((((
)))))
()(()
))((())
()()()()()()()()()()()()()()()
()()()()()()()()
())())))
))((((

输出样例 1989.out

19
1
42
10
493841617
0
【样例说明】
第一组询问的19种方法:



红色代表来自X,蓝色代表来自Y
【数据范围】
T<=8
XY长度不超过50

       这一题,我是班里为数不多的没有做出来的人。

   说说我的心路历程吧。看到这题,自然知道是DP。但是,我在判断状态合法上犯了难,我从构造合法括号序列的角度判断是否合法,把问题想得无比复杂。其实就是没有看清问题的本质——在除了最后之外的任意时刻,只要左括号的数量大于等于右括号,那么这就是个合法的序列

   至于为什么,其实很容易证明。如果右括号在前面找不到与之匹配的左括号,则必然非法。只要左括号能找到一个与之匹配的右括号,则必然合法。

   搞清楚了判断合法性的问题,这道题就很简单了。根据不同方案的定义进行分析,状态、方程就可以轻易得出了。

   f[i][j]表示X中选了i个字符,Y中选了j个字符组成合法括号序列的方案总数。在此状态为合法状态的情况下,最后一个字符要么是从X中来,要么是从Y中来,子问题就分别为f[i-1][j]和f[i][j-1]。因此,状态转移方程为:

   f[i][j]=f[i-1][j]+f[i][j-1];

   最后输出f[x.size()][y.size()]即可。

   PS:对于问题,不要笨笨地被题目条件所迷惑,要深入地思考,挖掘题目信息,将所谓的复杂问题简单化。

   代码如下:

#include#include#include#includeusing namespace std;const int MAXN=55;int t,a,b,len1,len2;int sum1[MAXN][2],sum2[MAXN][2];long long mod=1e9+7;long long f[MAXN][MAXN],sum[MAXN][MAXN];string x,y;void init(){len1=x.size();len2=y.size();memset(f,0,sizeof(f));memset(sum,0,sizeof(sum));for(int i=0;i>t;while(t--){cin>>x>>y;init();f[0][0]=1;for(int i=0;i<=len1;i++){for(int j=0;j<=len2;j++){if(i==0&&j==0)continue;a=sum1[i][0]+sum2[j][0];b=i+j-a;if(a

原创粉丝点击