Coloring Brackets CodeForces - 149D(区间DP)

Coloring Brackets

题目链接:CodeForces - 149D

题意:一个只由小括号组成的字符串,对括号进行染色,且满足以下三点:

  • Each bracket is either not colored any color, or is colored red, or is colored blue.
  • 每个括号有三种选择:不染色,染成红色,染成蓝色;
  • For any pair of matching brackets exactly one of them is colored. In other words, for any bracket the following is true: either it or the matching bracket that corresponds to it is colored.
  • 每对匹配的括号有且仅有一个括号被染色;
  • No two neighboring colored brackets have the same color.
  • 相邻的括号不能染成同种颜色,但是可以都不染色;

 思路:令dp[l][r][i][j]表示区间[l, r]中l, r分别染成i, j颜色(0<=i, j, <=2, 0表示不染色,1表示红色,2表示蓝色);

如果l和r是匹配的那么dp[l][r][i][j]=\sum_{i=0}^{2}\sum_{j=0}^{2}dp[l+1][r-1][i][j]

并且:

dp[l][r][0][0]=dp[l][r][1][1]=dp[l][r][2][2]=dp[l][r][1][2]=dp[l][r][2][1]=0;

 

如果l和r不匹配,那么dp[l][r][i][j]=\sum_{p=0}^{2}\sum_{q=0}^{2}dp[l][k[i][p]*dp[k+1][r][q][j]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
char s[710];
int match[710];
void Match(){
	int len=strlen(s);
	int pos[710], top=0;
	for(int i=0; i<len; i++){
		if(s[i]=='(') pos[top++]=i;
		else{
			if(top){
				top--;
				match[i]=pos[top];
				match[pos[top]]=i;
			}
			else match[i]=-1;
		}
	}
}
ll dp[710][710][3][3];
void dfs(int l, int r){
	if(l+1==r){
		dp[l][r][0][1]=dp[l][r][0][2]=dp[l][r][1][0]=dp[l][r][2][0]=1;
		return;
	}
	else if(match[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][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;
	}
	else{
		int k=match[l];
		dfs(l, k);
		dfs(k+1, r);
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++){
				if((i==1&&j==1)||(i==2&&j==2)) continue;
				dp[l][r][0][1]=(dp[l][r][0][1]+dp[l][k][0][i]*dp[k+1][r][j][1]%mod)%mod;
				dp[l][r][0][2]=(dp[l][r][0][2]+dp[l][k][0][i]*dp[k+1][r][j][2]%mod)%mod;
				dp[l][r][0][0]=(dp[l][r][0][0]+dp[l][k][0][i]*dp[k+1][r][j][0]%mod)%mod;
				dp[l][r][1][0]=(dp[l][r][1][0]+dp[l][k][1][i]*dp[k+1][r][j][0]%mod)%mod;
				dp[l][r][1][1]=(dp[l][r][1][1]+dp[l][k][1][i]*dp[k+1][r][j][1]%mod)%mod;
				dp[l][r][1][2]=(dp[l][r][1][2]+dp[l][k][1][i]*dp[k+1][r][j][2]%mod)%mod;
				dp[l][r][2][0]=(dp[l][r][2][0]+dp[l][k][2][i]*dp[k+1][r][j][0]%mod)%mod;
				dp[l][r][2][1]=(dp[l][r][2][1]+dp[l][k][2][i]*dp[k+1][r][j][1]%mod)%mod;
				dp[l][r][2][2]=(dp[l][r][2][2]+dp[l][k][2][i]*dp[k+1][r][j][2]%mod)%mod;
			}
		}
		return;
	}
}
int main(){
	scanf("%s", s);
	Match();
	int len=strlen(s);
	memset(dp, 0, sizeof(dp));
	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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值