https://codeforces.com/contest/149/problem/D
题意: 给一匹配的括号序列,要求每对括号恰有一个被染成蓝或红色,要求相邻的括号不同色,求方案数
思路:
- 首先考虑到每次搜的一个连续区间需要是合法的括号匹配。所以我开始想着直接把每一个子串的合理位置存下来。但是实际上最长串的每个合理位置都是固定的。因此开始括号匹配存下来即可
- 然后由于要求是合法子串,不方便递推,dfs记忆化搜索更加方便。考虑dfs
- dfs的过程中把判断当前子串是否合法写成函数,更加简洁明了。
- 考虑当前的l和r是不是一个对应的匹配,是的话直接搜(l+1,r-1),条件用check()函数做
- 考虑当前的l和r不是一个对应的匹配,那么就找到l的匹配或者r的匹配,都可以。继续搜并把答案乘起来。 比如( …) (…) (…) 这种状态,在dfs过程中实际上是被搜成(…)[ (…) (…) ]的,左边搜出答案后,后边搜出两个括号的答案变成[]再和左边合并即可。
调了挺久的一个坑,开始把stack写成了stack,然后疯狂mle以为爆栈。最后调了半天爆了RE发现问题。
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=710;
const int mod=1e9+7;
typedef long long LL;
inline LL read(){
LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){
if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){
x=x*10+ch-48;ch=getchar();}
return x*f;}
LL rightt[maxn],ans=0;
LL dp[maxn][maxn][3][3];
char s[maxn];
inline bool check(int l,int r,int p,int q){
if(rightt[l]!=r) return 0;///还需要递归分开
///以下为两个是一对的情况
if(p>0&&q>0) return 1;///两个都染色了
if(p==0&&q==0) return 1;///两个都没染色
return 0;
}
LL dfs(LL l,LL r,LL p,LL q){
if(dp[l][r][p][q]) return dp[l][r][p][q];
if(check(l,r,p,q)) return 0;///不合法直接返回0
if(l+1==r){
dp[l][r][p][q]=1;
return 1;
}
if(rightt[l]==r){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
if(j>0&&j==p) continue;
if(k>0&&k==q) continue;
dp[l][r][p][q]=(dp[l][r][p][q]+dfs(l+1,r-1,j,k)%mod)%mod;
}
}
return dp[l][r][p][q]%mod;
}
else{
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
if(j==k&&j>0) continue;
if(check(l,rightt[l],p,j)||check(rightt[l]+1,r,k,q)) continue;
dp[l][r][p][q]=(dp[l][r][p][q]+dfs(l,rightt[l],p,j)*dfs(rightt[l]+1,r,k,q)%mod)%mod;
}
}
return dp[l][r][p][q]%mod;
}
}
int main(void){
scanf("%s",s+1);LL n=strlen(s+1);
stack<LL>st;
st.push(1);
for(int i=2;i<=n;i++){
if(s[i]=='(') st.push(i);
else{
rightt[st.top()]=i;
st.pop();
}
}
memset(dp,0,sizeof(dp));
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
ans=(ans+dfs(1,n,i,j)%mod)%mod;
///debug(ans);
}
}
printf("%lld\n",ans);
return 0;
}