Coloring Brackets CodeForces - 149D(区间dp)

题目

Once Petya read a problem about a bracket sequence. He gave it much thought but didn’t find a solution. Today you will face it.

You are given string s. It represents a correct bracket sequence. A correct bracket sequence is the sequence of opening ("(") and closing (")") brackets, such that it is possible to obtain a correct mathematical expression from it, inserting numbers and operators between the brackets. For example, such sequences as “(())()” and “()” are correct bracket sequences and such sequences as “)()” and “(()” are not.

In a correct bracket sequence each bracket corresponds to the matching bracket (an opening bracket corresponds to the matching closing bracket and vice versa). For example, in a bracket sequence shown of the figure below, the third bracket corresponds to the matching sixth one and the fifth bracket corresponds to the fourth one.

You are allowed to color some brackets in the bracket sequence so as all three conditions are fulfilled:

Each bracket is either not colored any color, or is colored red, or is colored blue.
For any pair of matching brackets exactly one of them is colored. In other words, for any bracket the following is true: either it or the matching bracket that corresponds to it is colored.
No two neighboring colored brackets have the same color.
Find the number of different ways to color the bracket sequence. The ways should meet the above-given conditions. Two ways of coloring are considered different if they differ in the color of at least one bracket. As the result can be quite large, print it modulo 1000000007 (109 + 7).

Input
The first line contains the single string s (2 ≤ |s| ≤ 700) which represents a correct bracket sequence.

Output
Print the only number — the number of ways to color the bracket sequence that meet the above given conditions modulo 1000000007 (109 + 7).

Examples
Input
(())
Output
12
Input
(()())
Output
40
Input
()
Output
4

题意

每一对匹配的括号其中之一必须上色,另一必须黑色(无色)。
颜色有红、蓝、黑, 要求相邻两个单括号颜色不能相同,除了黑色(无色)。问给定符号有多少种上色方案。
建立dp[l][r][i][j],最后两维度,i代表左括号l位置的颜色,j代表右括号j位置的颜色。dp[l][r][i][j]内存该区间l涂i、r涂j状态下的上色方案数量。
先模拟栈(使用stack爆内存),通过pos数组可以找到任意位置对应的匹配括号的位置。
如果l+1 == r, 代表一对括号 ,i,j限定下,赋值为1。
如果l与r相匹配,dp[l][r][0][1] = (dp[l][r][0][1]+dp[l+1][r-1][i][j])
同理枚举该区间的其它上色方案,注意相对应符合的条件
如果不匹配,找到l相对应的mid,分成两个新区间,枚举所有符合状态的区间的次数相乘。
最后答案将dp[i][j]的所有上色方案的数量相加。
关于不匹配中mid可能越过j,但dp数组初始化为0,对结果无影响,还有dp[l+1][r-1][i][j]中 i == j本身是不符合题意的,但初始化后,可以不用对条件进行判断,对结果无影响。

#include <cstdio>
#include <stack>
#include <cstring>
int const maxn = 705;
#define mod 1000000007
using namespace std;
char s[maxn];
int pos[maxn], tmp[maxn];
long long dp[maxn][maxn][3][3];
void match(int len)
{
    int p=0;
    for(int i=0; i<len; i++)
    {
        if(s[i]=='(')
            tmp[p++]=i;
        else
        {
            pos[i]=tmp[p-1];
            pos[tmp[p-1]]=i;
            p--;
        }
    }
}
void dfs(int l, int r){
	int i, j;
	if(l+1 == r){
		dp[l][r][0][1] = 1; dp[l][r][0][2] = 1;
		dp[l][r][1][0] = 1; dp[l][r][2][0] = 1;
		return ;
	}
	else if(pos[l] == r){
		dfs(l+1, r-1);
		for(i = 0; i < 3; i++)
			for(j = 0; j < 3; j++){		
					if(j != 1)
						dp[l][r][0][1] = (dp[l][r][0][1]+dp[l+1][r-1][i][j])%mod;
					if(j != 2)	
						dp[l][r][0][2] = (dp[l][r][0][2]+dp[l+1][r-1][i][j])%mod;
					if(i != 1)
						dp[l][r][1][0] = (dp[l][r][1][0]+dp[l+1][r-1][i][j])%mod;
					if(i != 2)	
						dp[l][r][2][0] = (dp[l][r][2][0]+dp[l+1][r-1][i][j])%mod;		
			}
			return ;
	}
	else{
		int mid = pos[l];
		dfs(l, mid);
		dfs(mid+1, r);
		int p, q;
		for(i = 0; i < 3; i++)
			for(j = 0; j < 3; j++)
				for(p = 0; p < 3; p++)
					for(q = 0; q < 3; q++)
						if(!(q== 1 && p == 1) && !(q == 2 && p ==2))
							dp[l][r][i][j] =(dp[l][r][i][j] + (dp[l][mid][i][p]*dp[mid+1][r][q][j])%mod)%mod; 			
				 return ;
	}
}
int main(){
	int len, i, j;
	long long  ans; 
	while(~scanf("%s", s)){
		len = strlen(s);
		match(len);
		memset(dp, 0, sizeof(dp));
		dfs(0, len-1);
		ans = 0;
		for(i = 0; i < 3; i++)
			for(j = 0; j < 3; j++)
				ans = (ans + dp[0][len-1][i][j])%mod;
		printf("%lld\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值