CF149D Coloring Brackets
DP神题。。。
设\(dp[i][j][0/1/2][0/1/2]\)表示\([i,j]\)这个区间内端点取不染色/染红色/染蓝色三个状态然后转移。一个新\(trick\)就是这里的转移只要考虑这个区间内的串是合法的就可以了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define R register
#define LL long long
const int inf = 0x3f3f3f3f;
const int N = 700 + 5;
const int P = 1e9 + 7;
inline int read() {
char a = getchar(); int x = 0,f = 1;
for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
for(; a >= '0' && a <= '9' ;a = getchar()) x = x * 10 + a - '0';
return x * f;
}
int n;
char s[N];
int f[N][N][3][3]; // 700 * 700 * 3 * 3
int nxt[N];
int st[N], top;
inline void dp(int l, int r) {
if(l + 1 == r) {
f[l][r][0][1] = f[l][r][1][0] = f[l][r][2][0] = f[l][r][0][2] = 1;
return ;
}
if(nxt[l] == r) {
dp(l + 1, r - 1);
for(R int i = 0; i < 3; i++)
for(R int j = 0; j < 3; j++) {
if(j != 1) f[l][r][0][1] = (f[l][r][0][1] + f[l + 1][r - 1][i][j]) % P;
if(i != 1) f[l][r][1][0] = (f[l][r][1][0] + f[l + 1][r - 1][i][j]) % P;
if(j != 2) f[l][r][0][2] = (f[l][r][0][2] + f[l + 1][r - 1][i][j]) % P;
if(i != 2) f[l][r][2][0] = (f[l][r][2][0] + f[l + 1][r - 1][i][j]) % P;
}
return ;
}
else {
int m = nxt[l];
dp(l, m);
dp(m + 1, r);
for(R int i = 0; i < 3; i++)
for(R int j = 0; j < 3; j++)
for(R int u = 0; u < 3; u++)
for(R int v = 0 ; v < 3 ; v++ ) {
if(u == v && u != 0) continue;
f[l][r][i][j] = (f[l][r][i][j] + (1LL * f[l][m][i][u] * f[m + 1][r][v][j]) % P ) % P;
}
}
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
scanf("%s", s + 1);
n = strlen(s + 1);
for(R int i = 1; i <= n; i++) {
if(s[i] == '(') st[++top] = i;
else {
nxt[st[top]] = i;
top--;
}
}
dp(1, n);
int ans = 0;
for(R int i = 0; i < 3; i++ )
for(R int j = 0; j < 3; j++)
ans = ( ans + f[1][n][i][j] ) % P;
printf("%d\n", ans);
return 0;
}