CodeForces 149D 区间DP Coloring Brackets

染色有三个条件:

  • 对于每个点来说要么不染色,要么染红色,要么染蓝色
  • 对于每对配对的括号来说,有且只有一个一边的括号被染色
  • 相邻的括号不能染成相同的颜色

首先可以根据给出的括号序列计算出括号的配对情况,具体来说就是第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\n", DP(0, n - 1, 0, 0));
52 
53     return 0;
54 }
代码君

 

posted @ 2015-08-02 22:33  AOQNRMGYXLMV  阅读(326)  评论(0编辑  收藏  举报