题意:给一个给定括号序列,给该括号上色,上色有三个要求
1、只有三种上色方案,不上色,上红色,上蓝色
2、每对括号必须只能给其中的一个上色
3、相邻的两个不能上同色,可以都不上色
求0-len-1这一区间内有多少种上色方案;
思路:区间dp,dp[l][r][i][j]代表区间l~r(l图i颜色,r图j颜色)(0代表无色,1代表蓝色,2代表红色);
则
if(l+1==r) 说明就只有一对那么
dp[l][r][0][1]=1;
dp[l][r][1][0]=1;
dp[l][r][0][2]=1;
dp[l][r][2][0]=1;
if(l和r匹配)
往中间递归.dfs(l+1,r-1);
dp[l][r][0][1]=(dp[l][r][0][1]+dp[l+1][r-1][i][j])%mod;
dp[l][r][1][0]=(dp[l][r][1][0]+dp[l+1][r-1][i][j])%mod;
dp[l][r][0][2]=(dp[l][r][0][2]+dp[l+1][r-1][i][j])%mod;
dp[l][r][2][0]=(dp[l][r][2][0]+dp[l+1][r-1][i][j])%mod;
要注意相邻的两个颜色不能相同(可以同时无色);
else
找与之匹配的点(dfs(l,与左边匹配的点),dfs(与左边匹配的点+1,r))
dp[l][r][i][j]=(dp[l][r][i][j]+(dp[l][p][i][k]*dp[p+1][r][q][j])%mod)%mod;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=1e6+10;
const int mod=1e9+7;
using namespace std;
long long p[maxn],tmp[maxn],dp[710][710][3][3];
void getans(string s)//预处理括号之间的匹配
{
int cont=0;
int len=s.size();
for(int i=0; i<len; i++)
{
if(s[i]=='(')
tmp[cont++]=i;
else
{
p[i]=tmp[--cont];
p[tmp[cont]]=i;
}
}
}
void dfs(int l,int r)
{
if(l+1==r)
{
dp[l][r][0][1]=1;
dp[l][r][1][0]=1;
dp[l][r][0][2]=1;
dp[l][r][2][0]=1;
return ;
}
if(p[l]==r)
{
dfs(l+1,r-1);
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
{
if(j!=1)
dp[l][r][0][1]=(dp[l+1][r-1][i][j]+dp[l][r][0][1])%mod;
if(i!=1)
dp[l][r][1][0]=(dp[l+1][r-1][i][j]+dp[l][r][1][0])%mod;
if(j!=2)
dp[l][r][0][2]=(dp[l+1][r-1][i][j]+dp[l][r][0][2])%mod;
if(i!=1)
dp[l][r][2][0]=(dp[l+1][r-1][i][j]+dp[l][r][2][0])%mod;
}
return ;
}
else
{
int tmp=p[l];
dfs(l,tmp),dfs(tmp+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 o=0; o<3; o++)
{
if(k==0||o==0||k!=o)
dp[l][r][i][j]=(dp[l][r][i][j]+(dp[l][tmp][i][k]*dp[tmp+1][r][o][j])%mod)%mod;
}
}
}
int main()
{
string s;
while(cin>>s)
{
getans(s);
memset(dp,0,sizeof(dp));
int len=s.size();
dfs(0,len-1);
long long ans=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
ans=(dp[0][len-1][i][j]+ans)%mod;
printf("%lld\n",ans);
}
}