题目来源:click
一开始就把题目读错了…,以为给出的括号不是一定都是匹配的,想到组合数学那方面去过于复杂。(认真读题目)
题意给出的是一个完全匹配的字符串。
染色要求是相匹配的括号一定有一个要染色而且只有一个;相邻的括号不能染相同的颜色;每个括号只有三种情况,不上色,上红色,上蓝色。
首先我们应该要确定谁和谁相匹配,用一个数组ma[]来记录下标。
之前有过一个括号匹配的区间dp问题dp[i][j]表示从i-j区间有多少个匹配的括号。
这道题目也可以如此思考成区间dp,但是题目中增加了染色的问题,所以可以转化为一个四维的dp去写,dp[i][j][k1][k2]表示是区间的起点i染成k1,j染成k2的方法数,可从小到大递推出答案。题解非常巧妙的加上了dfs。
分为了三种情况去深搜:
1.当l==r-1的时候毫无疑问四种情况给上数值即可。
2.当ma[l]==r的时候,两端的括号相匹配:
分为染色情况匹配的括号只染色一个而且必须染一个。
即dp[l][r][][]+=dp[l+1][r+1][][],详情见代码。
3.两端的括号不匹配的话,找出中间的匹配值先进行dfs找出最优解,
之后相乘即可得到l-r区间的方法数,因为l-k,k+1-r互不影响但需要考虑k与k+1不能染相同的颜色。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<map>
#include<algorithm>
#include<queue>
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
char s[710];
int ma[710];
ll dp[710][710][3][3];
void solve(int l, int r)
{
if(r<l)
return ;
int i,j,k;
if(l==r-1)
{
dp[l][r][0][1]=1;
dp[l][r][0][2]=1;
dp[l][r][2][0]=1;
dp[l][r][1][0]=1;
return ;
}
if(ma[l]==r)
{
solve(l+1,r-1);
for(i=0;i<3;i++)
{
for(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;
}
}
return ;
}
int tmp=ma[l];
solve(l,tmp);
solve(tmp+1,r);
for(i=0;i<3;i++)//l
for(j=0;j<3;j++)//r
for(int k1=0;k1<3;k1++)//tmp
for(int k2=0;k2<3;k2++)//tmp+1
{
if((k1==1||k2==2)&&(k1==k2))
continue;
if((i==0&&(k1==1||k1==2))||(i==1&&(k1==0))||(i==2&&k1==0))
dp[l][r][i][j]=(dp[l][r][i][j]+(dp[l][tmp][i][k1]*dp[tmp+1][r][k2][j])%mod)%mod;
}
return ;
}
int main()
{
scanf("%s",s);
int i,j,n;
n=strlen(s);
stack<int>temp;
int len=0;
for(i=0;i<n;i++)
{
if(s[i]=='(')
{
temp.push(i);
continue;
}
else{
if(!temp.empty())
{
ma[i]=temp.top();
ma[temp.top()]=i;
temp.pop();
}
}
}
memset(dp,0,sizeof(dp));
solve(0,n-1);
ll ans=0;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
ans+=dp[0][n-1][i][j];
ans%=mod;
}
}
printf("%I64d",ans);
return 0;
}