题目大意
要求你对一个合法的括号序列进行染色,并且需要满足以下条件
1、要么不染色,要么染红色或者蓝色
2、对于任何一对括号,他们当中有且仅有一个被染色
3、相邻的括号不能染相同的颜色
题解
用区间dp[i][j][cl][cr]表示区间[i,j]被染色之后(第i个括号被染成cl色,第j个括号被染成cr色)的合法方案数
分为匹配和不匹配两种情况来处理,需要用到乘法原理,用记忆化比较好写~~~具体请看代码
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 705 #define MOD 1000000007 typedef long long LL; LL dp[MAXN][MAXN][3][3]; int match[MAXN],q[MAXN]; char s[MAXN]; bool check(int i,int j) { if(i==0||j==0||i!=j) return true; return false; } LL dfs(int l,int r,int cl,int cr) { LL &ret=dp[l][r][cl] [cr]; if(ret!=-1) return ret; ret=0; if(match[l]==r) { if((cl==0)^(cr==0)) { if(l+1==r) return ret=1; for(int i=0; i<3; i++) for(int j=0; j<3; j++) if(check(cl,i)&&check(j,cr)) ret=(ret+dfs(l+1,r-1,i,j))%MOD; } } else { for(int i=0; i<3; i++) for(int j=0; j<3; j++) if(check(i,j)) ret=(ret+dfs(l,match[l],cl,i)*dfs(match[l]+1,r,j,cr))%MOD; } return ret; } int main() { while(~scanf("%s",s+1)) { int n=strlen(s+1),t=1; for(int i=1; i<=n; i++) if(s[i]=='(') q[t++]=i; else match[q[--t]]=i; LL ans=0; memset(dp,-1,sizeof(dp)); for(int i=0; i<3; i++) for(int j=0; j<3; j++) ans=(ans+dfs(1,n,i,j))%MOD; printf("%I64d ",ans); } return 0; }