【题意】:给出一个长度为n的括号序列,括号满足两两匹配。
给出三个条件:
1.每个括号可以不染色,染蓝色或者染红色;
2.匹配的括号对有且仅有一个染色;
3.相邻的括号不能染相同的颜色。
问,满足以上三个条件的染色方案有多少种。
【题解】:好明显的dp题,因为一般这种求方案数的题目如果用纯数学知识来解是解不出的,而且限制条件一大堆。
设状态dp[l][r][c1][c2]表示[l,r]之间且l染成c1,r染成c2的合法方案数。
然后转移要分两种情况讨论:1.l与r匹配;2.l与r不匹配
转移就是运用乘法原理,要先预处理括号的匹配情况。
【代码】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 #include "algorithm"
5 #include "vector"
6 #include "queue"
7 #include "cmath"
8 #include "string"
9 #include "cctype"
10 #include "map"
11 #include "iomanip"
12 #include "stack"
13 using namespace std;
14 #define pb push_back
15 #define lc(x) (x << 1)
16 #define rc(x) (x << 1 | 1)
17 #define lowbit(x) (x & (-x))
18 #define ll long long
19 #define MAX 710
20 const int MOD = 1000000007;
21 string str;
22 ll dp[MAX][MAX][3][3];
23 int mat[MAX];
24 int s[MAX], top;
25
26 void pretreatment() {
27 top = 0;
28 for(int i = 0; i < str.length(); i++) {
29 if(str[i] == '(') s[top++] = i;
30 else mat[s[--top]] = i;
31 }
32 }
33
34 bool check(int a, int b) {
35 if(a == 0 || b == 0 || a != b) return true;
36 return false;
37 }
38
39 ll func(int l, int r, int c1, int c2) {
40 if(dp[l][r][c1][c2] != -1) return dp[l][r][c1][c2];
41 ll res = 0;
42 if(mat[l] == r) {
43 if((c1 == 0) ^ (c2 == 0)) {
44 if(l + 1 == r) return dp[l][r][c1][c2] = 1;
45 for(int i = 0; i < 3; i++) {
46 for(int j = 0; j < 3; j++) {
47 if(check(c1, i) && check(j, c2)) {
48 res += func(l + 1, r - 1, i, j);
49 }
50 }
51 }
52 } else return dp[l][r][c1][c2] = 0;
53 } else {
54 for(int i = 0; i < 3; i++) {
55 for(int j = 0; j < 3; j++) {
56 if(check(i, j))
57 res += func(l, mat[l], c1, i) * func(mat[l] + 1, r, j, c2);
58 }
59 }
60 }
61 return dp[l][r][c1][c2] = res % MOD;
62 }
63
64 int main() {
65 while(cin >> str) {
66 pretreatment();
67 memset(dp, -1, sizeof(dp));
68 ll ans = 0;
69 for(int i = 0; i < 3; i++)
70 for(int j = 0; j < 3; j++)
71 ans += func(0, str.length() - 1, i, j);
72 cout << ans % MOD << endl;
73 }
74 return 0;
75 }
76