染色有三个条件:
- 对于每个点来说要么不染色,要么染红色,要么染蓝色
- 对于每对配对的括号来说,有且只有一个一边的括号被染色
- 相邻的括号不能染成相同的颜色
首先可以根据给出的括号序列计算出括号的配对情况,具体来说就是第i个括号与R[i]个括号配对。
对于一个正规配对括号序列(correct bracket sequence),d(l, r, c1, c2)表示括号序列S[i]~S[j],i左边括号的颜色是c1,r右边的括号颜色是c2(0表示没有染色),这样的序列的染色方法数。
与S[i]配对的可能是S[j],但也可能是S[k] (i < k < j)
考虑用颜色c染这个序列的左括号还是右括号:
- 染左括号S[i]的话,只要c与c1不同即可。得到的方案数为d(i+1, k-1, c, 0) * d(k+1, r, 0, c2)
- 染与S[i]配对的右括号的话,要么所染S[j]的颜色c与c2不同,要么与S[i]配对的是S[k] (因为S[k]不受约束,可以染任意颜色)。得到的方案数为d(i+1, k-1, 0, c) * d(k+1, j, c, c2)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 8 typedef long long LL; 9 10 const int maxn = 700 + 10; 11 12 const LL M = 1000000007LL; 13 LL d[maxn][maxn][3][3]; 14 15 char s[maxn]; 16 17 int R[maxn], S[maxn]; 18 19 LL DP(int l, int r, int c1, int c2) 20 { 21 if(l > r) return 1LL; 22 LL& ans = d[l][r][c1][c2]; 23 if(ans >= 0) return ans; 24 ans = 0; 25 26 int k = R[l]; 27 for(int c = 1; c <= 2; c++) 28 { 29 if(k < r || c != c2) //color right 30 ans = (ans + DP(l + 1, k - 1, 0, c) * DP(k + 1, r, c, c2)) % M; 31 if(c != c1) //color left 32 ans = (ans + DP(l + 1, k - 1, c, 0) * DP(k + 1, r, 0, c2)) % M; 33 } 34 35 return ans; 36 } 37 38 int main() 39 { 40 scanf("%s", s); 41 int n = strlen(s); 42 43 int top = 0; 44 for(int i = 0; i < n; i++) 45 { 46 if(s[i] == '(') S[top++] = i; 47 else R[S[--top]] = i; 48 } 49 50 memset(d, -1, sizeof(d)); 51 printf("%I64d ", DP(0, n - 1, 0, 0)); 52 53 return 0; 54 }