区间DP。dp[i][j][h][k]表示[i,j]这段区间染色,左端点为颜色h,右端点为颜色k的方案数。
递推式很容易写出来。注意中间过程爆int。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int MOD = 1e9 + 7; const int maxn = 1000; char s[maxn]; long long dp[maxn][maxn][3][3]; int len; int link[maxn]; int Stack[maxn], top; void init() { len = strlen(s); for (int i = len - 1; i >= 0; i--) s[i + 1] = s[i]; memset(dp, 0, sizeof dp); } void work() { for (int i = 1; i <= len; i++) { if (i % 2 != 0) continue; for (int j = 1; j <= len; j++) { int st = j, en = st + i - 1; if (en > len) break; if (i == 2) { if (s[st] == '('&&s[en] == ')') { dp[st][en][1][0] = dp[st][en][2][0] = 1; dp[st][en][0][1] = dp[st][en][0][2] = 1; } continue; } if (link[st]==en) { for (int k = 0; k<3; k++) for (int h = 0; h<3; h++) if (k != 1) dp[st][en][1][0] = (dp[st][en][1][0] + dp[st + 1][en - 1][k][h]) % MOD; for (int k = 0; k<3; k++) for (int h = 0; h<3; h++) if (k != 2) dp[st][en][2][0] = (dp[st][en][2][0] + dp[st + 1][en - 1][k][h]) % MOD; for (int k = 0; k<3; k++) for (int h = 0; h<3; h++) if (h != 1) dp[st][en][0][1] = (dp[st][en][0][1] + dp[st + 1][en - 1][k][h]) % MOD; for (int k = 0; k<3; k++) for (int h = 0; h<3; h++) if (h != 2) dp[st][en][0][2] = (dp[st][en][0][2] + dp[st + 1][en - 1][k][h]) % MOD; continue; } int p = link[st]; for (int k = 0; k<3; k++) for (int h = 0; h<3; h++) for (int kk = 0; kk<3; kk++) for (int hh = 0; hh<3; hh++) if (!((kk == 1 && hh == 1) || (kk == 2 && hh == 2))) dp[st][en][k][h] = ( dp[st][en][k][h] + (dp[st][p][k][kk] * dp[p + 1][en][hh][h]) % MOD ) % MOD; } } long long ans = 0; for (int k = 0; k<3; k++) for (int h = 0; h<3; h++) ans = (ans + dp[1][len][k][h]) % MOD; printf("%lld ", ans); } void f() { memset(link, -1, sizeof link); top = -1; for (int i = 1; i <= len; i++) { if (top == -1) Stack[++top] = i; else { if (s[i] == ')') { link[Stack[top]] = i; top--; } else Stack[++top] = i; } } } int main() { while (~scanf("%s", s)) { init(); f(); work(); } return 0; }