题目链接:
Codeforces 149 D Coloring Brackets
题意:
给一个正确匹配的圆括号字符串,比如:
(),(()),(()())
,要对括号进行染色:
- 对每个括号可以选择不染色,染红色,或者染蓝色
- 每对匹配的括号必须有且仅有一个染色
- 相邻染色的括号的颜色不能一样
求最终的所有染色方案数?结果对
1e9+7
取模。
数据范围:字符串长度:
2≤|s|≤700
分析:
区间dp,可能比较容易想到,但是能想到标记状态和递归求解就比较难(?)了。。。。=_+
利用栈的思想可以获取每个括号的匹配括号的位置。
首先用0,1,2分别表示没被染色、被染成红色和被染成蓝色。
用
dp[a][b][s][e]
表示区间
[a,b]
且
s[a]
状态为
s
,
- 当
s[a]和s[b] 是匹配括号时,只需要枚举 s[a]和s[b] 的所有匹配情况然后递归求解区间 [a+1,b−1] ,但是要保证 s[a+1]和s[a] 以及 s[b−1]和s[b] 的颜色都不能一样。- 当 s[a]和s[b] 不是匹配括号时,需要找到 s[a] 的匹配括号位置 mid ,然后递归处理区间 [a,mid],[mid+1,b] ,两者相乘即可。
时间复杂度: O(9∗n2)
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <climits> #include <cmath> #include <ctime> #include <cassert> #define IOS ios_base::sync_with_stdio(0); cin.tie(0); using namespace std; typedef long long ll; const int MAX_N = 710; const ll mod = (ll)(1e9) + 7; int n, top; char s[MAX_N]; ll dp[MAX_N][MAX_N][3][3]; int good[3][3], bad[3][3], match[MAX_N], sta[MAX_N]; ll BiuBiu(int a, int b, int s, int e) { if (dp[a][b][s][e] != -1) return dp[a][b][s][e]; if (a + 1 == b) return dp[a][b][s][e] = (good[s][e] ? 1 : 0); ll res = 0; if (match[a] == b) { if (!good[s][e]) return dp[a][b][s][e] = 0; for (int i = 0; i < 3; ++i) { if (bad[s][i]) continue; for (int j = 0; j < 3; ++j) { if (bad[j][e]) continue; res = (res + BiuBiu(a + 1, b - 1, i, j)) % mod; } } } else { int mid = match[a]; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (bad[i][j]) continue; res = (res + BiuBiu(a, mid, s, i) * BiuBiu(mid + 1, b, j, e)) % mod; } } } return dp[a][b][s][e] = res; } int main() { good[0][1] = good[1][0] = good[0][2] = good[2][0] = 1; bad[1][1] = bad[2][2] = 1; while (~scanf("%s", s)) { n = strlen(s); top = 0; for (int i = 0; i < n; ++i) { if (s[i] == '(') sta[++top] = i; else { match[sta[top]] = i; match[i] = sta[top]; --top; } } memset(dp, -1, sizeof (dp)); ll ans = 0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { ans = (ans + BiuBiu(0, n - 1, i, j)) % mod; //printf("i = %d j = %d ans = %lld\n", i, j, ans); } } printf("%lld\n", ans); } return 0; }