设dp[l][r][x][y]表示区间[l,r]左端染的色是x,右端染的色是y的方案数
其中x,y取0,1,2,分别表示不染色,染红色,染蓝色
1.l+1==r,那么它们一定就是一对匹配的括号,因为我们枚举的都是合理的情况,此时,只可能有四种情况,方案数均为1,即:dp[l][r][0][1] = dp[l][r][1][0] = 1;dp[l][r][0][2] = dp[l][r][2][0] = 1;
2.l和r是一对匹配的括号,此时,区间被分为两部分,两端点以及区间[l+1,r-1],那么我们可以先算出区间[l+1,r-1]的方案数,再由此状态转移到当前区间,两端点情况也就四种,不冲突即可转移
3.l和r不是一对匹配的括号,此时,区间也可被分成两部分,区间[l,mid]和区间[mid+1,r],其中mid为l所对应与之匹配的括号,这样,一个合法的括号序列变成两个合法的括号序列,将它们分别求出方案数,再将不冲突的情况组合起来即可
//设dp[l][r][x][y]表示区间[l,r]左端染的色是x,右端染的色是y的方案数
//其中x,y取0,1,2,分别表示不染色,染红色,染蓝色
#include<iostream>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 705;
const int mod = 1000000007;
ll dp[maxn][maxn][3][3];
string str;
stack<int> s;
map<int, int> pos;
//找当前括号对应匹配括号的下标
void get_match() {
for (int i=0; i<str.size(); ++i) {
if (str[i] == '(')
s.push(i);
else {
pos[i] = s.top();
pos[s.top()] = i;
s.pop();
}
}
}
void dfs(int l, int r) {
//当区间长度只有2时候
//两个括弧一定是配对的,因为我们考虑的所有区间都是配对合法的区间
//
if (l+1 == r) {
dp[l][r][0][1] = dp[l][r][1][0] = 1;
dp[l][r][0][2] = dp[l][r][2][0] = 1;
return ;
}
//如果是匹配区间
if (pos[l] == r) {
//算里面的区间
dfs(l+1, r-1);
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j) {
//枚举所有情况,相邻的颜色不能相同 ,可以相邻两边都不染色
//但匹配的括号里面必须有一个染色,且只能由一个染色
//当区间尾部染色不为1
if (j != 1)
//开头不染,末尾染1
// 开头可以不染,但末尾颜色不能为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;
}
return ;
}
//如果不是匹配区间
//去找匹配区间
int mid = pos[l];
dfs(l, mid);
dfs(mid+1, r);
//将两边的情况合并
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
for (int k=0; k<3; ++k)
for (int s=0; s<3; ++s)
if (!(k==1&&s==1) && !(k==2&&s==2))
dp[l][r][i][j] = (dp[l][r][i][j]+dp[l][mid][i][k]*dp[mid+1][r][s][j])%mod;
}
int main() {
cin >> str;
get_match();
dfs(0, str.size()-1);
ll ans = 0;
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
ans = (ans+dp[0][str.size()-1][i][j])%mod;
cout << ans << endl;
return 0;
}