问题:给你一个长度为n的合法括号序列,你要对每一对括号的其中一个半括号(必须并且只能为一个)染色,有两种颜色可以选择。要求染完色后,序列里不存在相邻的位置是同种颜色的(两个都未染色的算合法)。求一共有几种染色方案。答案取模1e9+7。
思路: 区间dp。记dp[l][r][i][j]为对区间[l,r],s[l]染颜色i,s[r]染颜色j时的合法方案有几种。(1<=l<=r<=n,0<=i<=2,0<=j<=2)这里0表示未染色,1,2分别代表颜色1和颜色2。
我们用栈可以O(n)的预处理出每一个位置i上的半括号与它匹配的另一半在哪个位置记为match[i]。
因为题目染色条件的限制。
当l===r时,dp[l][r][][]显然为0。
当r=l+1时,只有 1 0,2 0,0 1,0 2。这四种方案时合法的。所以dp[l][r][1][0]=dp[l][r][2][0]=dp[l][r][0][1]=dp[l][r][0][2]=1,其他都为0。
当r>l+1且l和r正好是一对匹配括号时。就递归找[l+1,r-1]的合法方案。
当l和r不是一对匹配括号时。就递归找[l,match[l]],[match[l]+1,r]这两个区间。总的染色方案就等于这两个子区间的合法方案相乘。
因为颜色的约束,具体状态转移见代码,挺好理解的。
如果我没算错的话,这道题的做法时间复杂度应该是O(n)的。
AC代码:
//#include<bits/stdc++.h> #include<set> #include<map> #include<stack> #include<cmath> #include<ctime> #include<queue> #include<cstdio> #include<string> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<unordered_map> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef pair<ll, int> pli; typedef pair<int, ll> pil; #define pb push_back #define X first #define Y second inline ll gcd(ll a, ll b) { while (b != 0) { ll c = a % b; a = b; b = c; }return a < 0 ? -a : a; } inline ll lcm(ll a, ll b) { return (a * b) / gcd(a, b); } inline ll lowbit(ll x) { return x & (-x); } const double PI = 3.14159265358979323846; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f; const ll mod = 1e9 + 7; inline char nc() { static char buf[1 << 21], * p1 = buf, * p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++; } inline ll rd() { //#define getchar nc ll x = 0, f = 1; char ch = getchar(); while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); } return x * f; } const double eps = 1e-6; const int M = 1e6 + 10; const int N = 1e5 + 10; ll dp[710][710][3][3]; int match[710]; char s[N]; int n; void dfs(int l, int r) { if (l == r) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { dp[l][r][i][j] = 0; } } return; } if (l + 1 == r) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i == j || (i > 0 && j > 0))dp[l][r][i][j] = 0; else dp[l][r][i][j] = 1; } } } else if (match[l] == r) { dfs(l + 1, r - 1); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++)dp[l][r][i][j] = 0; } for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (j != 1)dp[l][r][0][1] = (dp[l][r][0][1] + dp[l + 1][r - 1][i][j]) % mod; if (j != 2)dp[l][r][0][2] = (dp[l][r][0][2] + dp[l + 1][r - 1][i][j]) % mod; if (i != 1)dp[l][r][1][0] = (dp[l][r][1][0] + dp[l + 1][r - 1][i][j]) % mod; if (i != 2)dp[l][r][2][0] = (dp[l][r][2][0] + dp[l + 1][r - 1][i][j]) % mod; } } } else { dfs(l, match[l]), dfs(match[l] + 1, r); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++)dp[l][r][i][j] = 0; } for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { if ((y == 0 && x == 0) || (x != y)) { dp[l][r][i][j] = (dp[l][r][i][j] + dp[l][match[l]][i][x] * dp[match[l] + 1][r][y][j] % mod) % mod; } } } } } } } int sta[N]; int main() { scanf("%s", s + 1); n = strlen(s + 1); int p = 0; for (int i = 1; i <= n; i++) { if (s[i] == '(')sta[++p] = i; else { match[sta[p]] = i; match[i] = sta[p]; p--; } } dfs(1, n); ll ans = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { ans += dp[1][n][i][j]; ans %= mod; } } cout << ans << endl; }