题解
- 首先明确括号的匹配是惟一的。所以用一个栈模拟,用数组match记录左括号对应的右括号的位置。
- 染色要求是:
- 可以染红或蓝或者无色。
- 每一对括号有且仅有一个染色。
- 相邻不能染相同的颜色,但可以都不染色。
- dp[i][j][p][q]表示i染p,j染q的区间方案数。0表示不染色,1表示红色,2表示蓝色。
- dfs区间一遍。dfs(l,r),如果l和r匹配上,那么dfs(l+1,r-1);否则dfs(l,match(l))和dfs(match(l)+1,r);边界条件l+1 = r(l和r一定是匹配的)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int const MOD = 1e9 + 7;
int const N = 700 + 10;
char s[N];
ll dp[N][N][3][3];
int mp[N];
void Init(int n){
stack<int>st;
for(int i=0;i<n;i++){
if(s[i] == '(') st.push(i);
else{
mp[st.top()] = i;
st.pop();
}
}
}
void dfs(int l,int r){
if(l + 1 == r){ //保证每一对括号有且仅有一个上色
dp[l][r][1][0] = dp[l][r][0][1] = 1;
dp[l][r][2][0] = dp[l][r][0][2] = 1;
}else if(mp[l] == r){ //配对成功
dfs(l+1,r-1);
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
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;
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;
}
}
}else{
dfs(l,mp[l]); dfs(mp[l]+1,r);
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int p=0;p<3;p++){
for(int q=0;q<3;q++){
if(j != p || p == 0)
dp[l][r][i][q] = (dp[l][r][i][q] + dp[l][mp[l]][i][j] * dp[mp[l]+1][r][p][q]) % MOD;
}
}
}
}
}
}
int main(){
scanf(" %s",s);
int len = strlen(s);
Init(len);
dfs(0,len-1);
ll ans = 0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++)
ans = (ans + dp[0][len-1][i][j]) % MOD;
}
printf("%lld\n",ans);
return 0;
}