题目传送门
首先看到这个题目,一定要用栈,
废话
我们可以发现对于一个括号,不管它是左括号还是右括号,对他有影响的只有3个位置他的左边括号的颜色 他的右边括号的颜色 他的对应的括号的颜色
对于1,2两个问题,可以利用普通的dp枚举,对于第3个问题,处理这个问题的括号,就可以处理把这个问题删掉的这个区间,所以就可以区间dp
f
[
l
]
[
r
]
[
x
]
[
y
]
表
示
l
f[l][r][x][y]表示l
f[l][r][x][y]表示l~
r
这
个
区
间
,
l
的
颜
色
为
x
,
r
的
颜
色
为
y
的
方
案
数
r这个区间,l的颜色为x,r的颜色为y的方案数
r这个区间,l的颜色为x,r的颜色为y的方案数
m
a
t
c
h
[
x
]
表
示
x
是
左
括
号
的
时
候
,
它
对
应
的
右
括
号
在
哪
(
可
以
用
栈
做
)
match[x]表示x是左括号的时候,它对应的右括号在哪(可以用栈做)
match[x]表示x是左括号的时候,它对应的右括号在哪(可以用栈做)
f
[
l
]
[
r
]
[
x
]
[
y
]
=
Σ
i
=
0
3
Σ
j
=
0
3
{
f
[
l
+
1
]
[
r
−
1
]
[
i
]
[
j
]
(
m
a
t
c
h
[
l
]
=
r
)
f
[
l
]
[
m
a
t
c
h
[
l
]
]
[
x
]
[
i
]
∗
f
[
m
a
t
c
h
[
l
]
+
1
]
[
r
]
[
y
]
[
i
]
(
i
,
j
满
足
相
邻
的
性
质
)
f[l][r][x][y]= \Sigma _{i=0}^3\Sigma _{j=0}^3\begin{cases}f[l+1][r-1][i][j](match[l]=r)\\ f[l][match[l]][x][i]*f[match[l]+1][r][y][i](i,j满足相邻的性质) \end{cases}
f[l][r][x][y]=Σi=03Σj=03{f[l+1][r−1][i][j](match[l]=r)f[l][match[l]][x][i]∗f[match[l]+1][r][y][i](i,j满足相邻的性质)
用记忆化搜索即可(还有一些细节的处理)
#include<bits/stdc++.h>
using namespace std;
const int N=710;
#define Mod 1000000007
#define ll long long
char s[N];int n,match[N];ll ans;
stack<int>sta;ll f[N][N][3][3];
#define res f[l][r][x][y]
ll dfs(int l,int r,int x,int y){
if(res!=-1)return res;res=0;
if(l+1==r)return res=((x>0)!=(y>0));
if(match[l]==r){
if((x>0)==(y>0))return 0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if((i==0||i!=x)&&(j==0||j!=y))
res=(res+dfs(l+1,r-1,i,j))%Mod;
return res;
}
//l~match[l] match[l]+1~r
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(i==0&&j==0||i!=j)
res=(res+dfs(l,match[l],x,i)*dfs(match[l]+1,r,j,y)%Mod)%Mod;
return res;
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%s",s+1);ll ans=0;
int n=strlen(s+1);
for(int i=1;i<=n;i++)
if(s[i]=='(')sta.push(i);
else match[sta.top()]=i,sta.pop();
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
ans=(ans+dfs(1,n,i,j))%Mod;
printf("%lld",ans);
return 0;
}