CF149D:区间DP

CF149D

题解

  • 首先明确括号的匹配是惟一的。所以用一个栈模拟,用数组match记录左括号对应的右括号的位置。
  • 染色要求是:
  1. 可以染红或蓝或者无色。
  2. 每一对括号有且仅有一个染色。
  3. 相邻不能染相同的颜色,但可以都不染色。
  • dp[i][j][p][q]表示i染p,j染q的区间方案数。0表示不染色,1表示红色,2表示蓝色。
  • dfs区间一遍。dfs(l,r),如果l和r匹配上,那么dfs(l+1,r-1);否则dfs(l,match(l))和dfs(match(l)+1,r);边界条件l+1 = r(l和r一定是匹配的)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int const MOD = 1e9 + 7;
int const N = 700 + 10;
char s[N];
ll dp[N][N][3][3];
int mp[N];
void Init(int n){
	stack<int>st;
	for(int i=0;i<n;i++){
		if(s[i] == '(')	st.push(i);
		else{
			mp[st.top()] = i;
			st.pop();
		}
	}
}
void dfs(int l,int r){
	if(l + 1 == r){  //保证每一对括号有且仅有一个上色
		dp[l][r][1][0] = dp[l][r][0][1] = 1;
		dp[l][r][2][0] = dp[l][r][0][2] = 1;
	}else if(mp[l] == r){  //配对成功
		dfs(l+1,r-1);
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				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;
				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;
			}
		}
	}else{
		dfs(l,mp[l]);	dfs(mp[l]+1,r);
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				for(int p=0;p<3;p++){
					for(int q=0;q<3;q++){
						if(j != p || p == 0)
							dp[l][r][i][q] = (dp[l][r][i][q] + dp[l][mp[l]][i][j] * dp[mp[l]+1][r][p][q]) % MOD;
					}
				}
			}
		}
	}
}
int main(){
	scanf(" %s",s);
	int len = strlen(s);
	Init(len);
	dfs(0,len-1);
	ll ans = 0;
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++)
			ans = (ans + dp[0][len-1][i][j]) % MOD;
	}
	printf("%lld\n",ans);
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/89224830