
本文共 4607 字,大约阅读时间需要 15 分钟。
题目描述
Petya遇到了一个关于括号序列的问题: 给定一个字符串 S S S,它代表着正确的括号序列,即 “ ( ( (” 与 “ ) ) )” 是匹配的。例如:“ ( ( ) ) ( ) (())() (())()” 和 “ ( ) () ()”是正确的,“ ) ( ) )() )()”与“ ( ( ) (() (()”则不是正确的。 在正确的括号序列中,一个左边的括号一定是匹配一个右边的括号(反之亦然)。例如,在下图中,第 3 3 3 个括号匹配第 6 6 6 个括号,第 4 4 4 个括号匹配第 5 5 5 个括号。
现在你需要对一个正确的括号序列做涂色操作,严格满足以下三个条件:
1、每个括号要么不涂色,要么涂红色,要么涂蓝色。
2、一对匹配的括号需要且只能将其中一个涂色。
3、相邻的括号不能涂上同一种颜色(但是可以都不涂颜色)。
求:给整个括号序列涂上颜色的方案数,答案可能比较大,对 1 0 9 + 7 10^9+7 109+7 取模。
输入格式
输入的第一行包含一个字符串 s s s,( 2 < = ∣ s ∣ < = 700 2 <= |s| <= 700 2<=∣s∣<=700),代表一个正确的括号序列。
输出格式
输出方案数。(对 1 0 9 + 7 10^9 + 7 109+7 取模)
样例
输入
(()())
输出
40
分析
读者不难想到这是一道区间DP。当我们定义 d p [ l ] [ r ] dp[l][r] dp[l][r]为左端点为 l l l,右端点为 r r r的方案总数会发现,我们不知道某个点到底是什么颜色,规则的第二点和第三点就不好计算。
不妨令 d p [ l ] [ r ] [ p ] [ q ] dp[l][r][p][q] dp[l][r][p][q]为左端点为 l l l,右端点为 r r r,且 a [ l ] a[l] a[l]的颜色为 c o l o r [ p ] color[p] color[p], a [ r ] a[r] a[r]的颜色为 c o l o r [ q ] color[q] color[q]的方案总数。(我写的 c o l o r [ 0 ] color[0] color[0]是无色)
DP_1
若 l e n = 2 len=2 len=2,此时有
dp[l][r][1][0] = 1; dp[l][r][0][1] = 1;dp[l][r][2][0] = 1; dp[l][r][0][2] = 1;
DP_2
在 d p [ l ] [ r ] dp[l][r] dp[l][r]中,若 a [ l ] a[l] a[l]和 a [ r ] a[r] a[r]是一组匹配的括号,那么
dp[l][r][1][0] = (dp[l + 1][r - 1][2][2] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][0][1] + dp[l + 1][r - 1][2][0] + dp[l + 1][r - 1][0][2] + dp[l + 1][r - 1][2][1]) % Mod;dp[l][r][2][0] = (dp[l + 1][r - 1][1][2] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][0][1] + dp[l + 1][r - 1][1][0] + dp[l + 1][r - 1][0][2] + dp[l + 1][r - 1][1][1]) % Mod;dp[l][r][0][1] = (dp[l + 1][r - 1][2][2] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][1][0] + dp[l + 1][r - 1][2][0] + dp[l + 1][r - 1][0][2] + dp[l + 1][r - 1][1][2]) % Mod;dp[l][r][0][2] = (dp[l + 1][r - 1][2][1] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][1][0] + dp[l + 1][r - 1][0][1] + dp[l + 1][r - 1][2][0] + dp[l + 1][r - 1][1][1]) % Mod;
至于为什么,我不想多说了,,,其实就是把所有可行的情况加起来。当然你也可以用四重循环。
DP_3
若不匹配,可以找到与 a [ l ] a[l] a[l]匹配的右括号 a [ k ] a[k] a[k](用栈 s t a c k stack stack),把 d p [ l ] [ r ] dp[l][r] dp[l][r]分成 d p [ l ] [ k ] dp[l][k] dp[l][k]和 d p [ k + 1 ] [ r ] dp[k+1][r] dp[k+1][r],我们如果还像上面那样一个一个列举,会很累的…用四重循环枚举 a [ l ] a[l] a[l]、 a [ k ] a[k] a[k]、 a [ k + 1 ] a[k+1] a[k+1]、 a [ r ] a[r] a[r]的颜色,只用剪掉 a [ k ] a[k] a[k]和 a [ k + 1 ] a[k +1] a[k+1]颜色相同的情况就行了。当然情况二用这个也会简单很多。( l ≤ k ≤ r l \leq k \leq r l≤k≤r)
for(int o = 0; o < 3; o ++) { for(int p = 0; p < 3; p ++) { for(int q = 0; q < 3; q ++) { for(int s = 0; s < 3; s ++) { if((p == 1 && q == 1) || (p == 2 && q == 2)) continue; dp[l][r][o][s] = (dp[l][r][o][s] + dp[l][Match[l]][o][p] * dp[Match[l] + 1][r][q][s]) % Mod; } } }}
代码
#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <stack>#define LL long longusing namespace std;const int Mod = 1000000007, MAXN = 705;char a[MAXN];int n, r, Match[MAXN];LL dp[MAXN][MAXN][3][3], ans;stack <int> sk;int main() { // freopen("coloring.in", "r", stdin);// freopen("coloring.out", "w", stdout); scanf("%s", a + 1); n = strlen(a + 1); for(int i = 1; i <= n; i ++) { if(a[i] == '(') sk.push(i); else { Match[sk.top()] = i; sk.pop(); } } for(int len = 2; len <= n; len ++) { for(int l = 1; l <= (n - len + 1); l ++) { r = l + len - 1; if(l == (r - 1)) { dp[l][r][1][0] = 1; dp[l][r][0][1] = 1; dp[l][r][2][0] = 1; dp[l][r][0][2] = 1; } else if(Match[l] == r) { dp[l][r][1][0] = (dp[l + 1][r - 1][2][2] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][0][1] + dp[l + 1][r - 1][2][0] + dp[l + 1][r - 1][0][2] + dp[l + 1][r - 1][2][1]) % Mod; dp[l][r][2][0] = (dp[l + 1][r - 1][1][2] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][0][1] + dp[l + 1][r - 1][1][0] + dp[l + 1][r - 1][0][2] + dp[l + 1][r - 1][1][1]) % Mod; dp[l][r][0][1] = (dp[l + 1][r - 1][2][2] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][1][0] + dp[l + 1][r - 1][2][0] + dp[l + 1][r - 1][0][2] + dp[l + 1][r - 1][1][2]) % Mod; dp[l][r][0][2] = (dp[l + 1][r - 1][2][1] + dp[l + 1][r - 1][0][0] + dp[l + 1][r - 1][1][0] + dp[l + 1][r - 1][0][1] + dp[l + 1][r - 1][2][0] + dp[l + 1][r - 1][1][1]) % Mod; } else if(l <= Match[l] && Match[l] <= r) { for(int o = 0; o < 3; o ++) { for(int p = 0; p < 3; p ++) { for(int q = 0; q < 3; q ++) { for(int s = 0; s < 3; s ++) { if((p == 1 && q == 1) || (p == 2 && q == 2)) continue; dp[l][r][o][s] = (dp[l][r][o][s] + dp[l][Match[l]][o][p] * dp[Match[l] + 1][r][q][s]) % Mod; } } } } } } } for(int i = 0; i <= 2; i ++) { for(int j = 0; j <= 2; j ++) { ans = (ans + dp[1][n][i][j]) % Mod; } } printf("%lld", ans); return 0;}
发表评论
最新留言
关于作者
