1. 题面梗概
中译中: 给一个合法的括号序列。你要给括号染色:红色、蓝色或不染。要求:
-
每对配对的括号,恰好有一个有色。
-
相邻的括号颜色不能相同(除非都是不染色)。
求总方案数。
2. 逻辑推导
合法括号匹配显然很符合递归的特性,这引导我们使用区间 DP 递归求解。
2.1 结构分析
我们发现,合法的括号序列只有两种组合情况:1. (A) 嵌套型;2. AB 拼接型。这就意味着,区间 [l,r] 的方案数只取决于它的子结构。
因此不难想到,定义 f[l][r] 表示区间 [l,r] 的合法序列括号总方案数。但因为相邻括号颜色不能相同,所以我们必须知道左右端点染了什么颜色。
从而我们扩展状态,定义 f[l][r][cl][cr] 为区间 [l,r],左端点染 cl 色,右端点染 rl 色的方案数。
2.2 递归
从两个合法情况进行分析,我们首先需要处理出每个括号的对应的匹配位置 match[i]。
2.3 结论
如此我们就解决了这个复杂的区间DP问题,解决方案就是新增两个状态维度,用于处理转移。
2. 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| #include <bits/stdc++.h>#include<bits/stdc++.h> using namespace std;
const int maxn = 1005; const int mod = 1000000007;
string s; int dp[maxn][maxn][3][3]; int p[maxn]; int n;
bool ok( int c1, int c2 ) { return !( c1 > 0 && c2 > 0 && c1 == c2 ); }
bool check( int cl, int cr ) { return ( cl > 0 ) ^ ( cr > 0 ); }
long long dfs( int l, int r, int cl, int cr ) { if( dp[l][r][cl][cr] != -1 ) return dp[l][r][cl][cr];
long long ans = 0;
if( l + 1 == r ) { return dp[l][r][cl][cr] = check( cl, cr ); }
if( p[l] == r ) { if( !check( cl, cr ) ) return dp[l][r][cl][cr] = 0; for( int ncl = 0; ncl < 3; ++ ncl ) { for( int ncr = 0; ncr < 3; ++ ncr ) { if( !ok( cl, ncl ) || !ok( cr, ncr ) ) continue; ans = ( ans + dfs( l + 1, r - 1, ncl, ncr ) ) % mod; } } } else { int k = p[l]; for( int mcl = 0; mcl < 3; ++ mcl ) { for( int mcr = 0; mcr < 3; ++ mcr ) { if( !ok( mcl, mcr ) ) continue; long long lres = dfs( l, k, cl, mcl ); long long rres = dfs( k+1, r, mcr, cr ); if( lres && rres ) { ans = ( ans + lres * rres ) % mod; } } } }
return dp[l][r][cl][cr] = ans; }
int main() { cin >> s; n = s.length( ); s = ' ' + s;
stack<int> stk; for( int i = 1; i <= n; ++ i ) { if( s[i] == '(' ) stk.push( i ); else if( !stk.empty( ) ) { p[stk.top( )] = i; p[i] = stk.top( ); stk.pop( ); } }
memset( dp, -1, sizeof( dp ) );
long long ans = 0; for( int i = 0; i < 3; ++ i ) { for( int j = 0; j < 3; ++ j ) { ans = ( ans + dfs( 1, n, i, j ) ) % mod; } }
cout << ans << '\n'; return 0; }
|
4. 复盘