题目链接: http://codeforces.com/contest/149/problem/D
-----------------------------------------------------------------------------------------------
半年前这道区间$DP$磨叽了一天不会 现在感觉是很多地方的题解没写清楚 自己多想会就好了
首先我们用$F[L][R][c1][c2]$表示从$L$到$R$这段区间左右端点颜色分别为$c1,c2$的方案数
$($颜色为$0$代表无色$)$然后用记忆化搜索求解
做的过程中要分两种情况进行讨论
$1.$若$L,R$为匹配的括号 则对区间$[L + 1,R - 1]$进行讨论
2.否则对$[L,m[L]],[m[L] + 1, R]$进行讨论$(m$为该左括号匹配的右括号位置$)$
最后对于$L + 1= R$的区间特判即可
-----------------------------------------------------------------------------------------------
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 const int N = 710, mod = 1e9 + 7; 7 char s[N]; 8 long long f[N][N][3][3]; 9 bool check[3][3] = {{0, 1, 1},{1, 0, 0},{1, 0, 0}}; 10 bool check2[3][3] = {{1, 1, 1},{1, 0, 1},{1, 1, 0}}; 11 int m[N], st[N]; 12 int n, top; 13 long long ans = 0; 14 long long dfs(int L, int R, int c1, int c2) 15 { 16 if(f[L][R][c1][c2] != -1) 17 return f[L][R][c1][c2]; 18 f[L][R][c1][c2] = 0; 19 if(m[L] == R) 20 { 21 if(!check[c1][c2]) 22 return 0; 23 if(L + 1 == R) 24 return f[L][R][c1][c2] = 1; 25 for(int i = 0; i < 3; ++i) 26 for(int j = 0; j < 3; ++j) 27 if(check2[c1][i] && check2[j][c2]) 28 f[L][R][c1][c2] = (f[L][R][c1][c2] + 29 dfs(L + 1, R - 1, i, j)) % mod; 30 } 31 else 32 { 33 for(int i = 0; i < 3; ++i) 34 for(int j = 0; j < 3; ++j) 35 { 36 if(check2[i][j] && check[c1][i]) 37 f[L][R][c1][c2] = (f[L][R][c1][c2] + 38 dfs(L, m[L], i, c1) * dfs(m[L] + 1, R, c2, j)) % mod; 39 } 40 } 41 return f[L][R][c1][c2]; 42 } 43 int main() 44 { 45 scanf("%s", s + 1); 46 n = strlen(s + 1); 47 for(int i = 1; i <= n; ++i) 48 if(s[i] == '(') 49 st[top ++] = i; 50 else 51 m[st[-- top]] = i; 52 memset(f, -1, sizeof f); 53 for(int i = 0 ; i < 3; ++i) 54 for(int j = 0; j < 3; ++j) 55 ans += dfs(1, n, i, j); 56 printf("%lld ", ans % mod); 57 return 0; 58 }