cf149D Coloring Brackets

题目链接:https://vjudge.net/problem/CodeForces-149D#author=algo11318030

题意:给定一个括号序列,对这个括号序列进行染色,有以下要求:每个字符有三种情况:不染色,染成红色,染成蓝色;每对匹配的括号,有且仅有一个字符被染色;所有相邻的两个字符,不能染成同一种颜色。求染色的方案数

这题一开始想用递推写,后来发现不太写的出来。网上查了一下,基本都是用dfs的形式写的,到现在也不知道有没有递推的写法。设f[l][r][0/1/2][0/1/2]表示从i到j的括号,i不染色/染成红色/染成蓝色的方案数。dfs的过程中,主要依据括号的匹配来递归。有如下几种情况:

1. r-l=1,这是dfs的边界,且由过程2和3可得l,r是一对匹配的括号,则有f[l][r][0][1]=f[l][r][1][0]=f[l][r][0][2]=f[l][r][2][0]=1;

2. l和r是一对匹配的括号,则由相邻括号不同色,且匹配的括号有且仅有一个字符被染色,递归区间(l+1,r-1),则有

f[l][r][0][1]=f[l+1][r-1][0][2]+f[l+1][r-1][2][0]

f[l][r][0][2]=f[l+1][r-1][1][0]+f[l+1][r-1][2][0]

f[l][r][1][0]=f[l+1][r-1][0][2]+f[l+1][r-1][2][0]

f[l][r][2][0]=f[l+1][r-1][0][1]+f[l+1][r-1][1][0]

3. l和r不是一对匹配的括号,则找到l的匹配的括号m[l](这可以由一个预处理得出),分别递归区间(l,m[l])和(m[l]+1,r),最后根据乘法原理求出:f[l][r][i][j]+=Σf[l][m[l]][i][k]*f[m[l]+1][r][t][j]),0<i,j,k,t<3,k=0或t=0或k!=t

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int mod=1e9+7;
ll f[710][710][3][3];
int m[710],n,i,j;
string s;

void dp(int l,int r){
	if (l+1==r){ //*
	  f[l][r][0][1]=f[l][r][1][0]=f[l][r][0][2]=f[l][r][2][0]=1;
	  return;
	}
	if (m[l]==r){
	  dp(l+1,r-1); //*
	  for (int i=0;i<3;i++)	
	    for (int j=0;j<3;j++){
	      if (j!=1) f[l][r][0][1]=(f[l][r][0][1]+f[l+1][r-1][i][j])%mod;
	      if (i!=1) f[l][r][1][0]=(f[l][r][1][0]+f[l+1][r-1][i][j])%mod;
	      if (j!=2) f[l][r][0][2]=(f[l][r][0][2]+f[l+1][r-1][i][j])%mod;
	      if (i!=2) f[l][r][2][0]=(f[l][r][2][0]+f[l+1][r-1][i][j])%mod;
		}
	}
	else {
      dp(l,m[l]); dp(m[l]+1,r); //*
      for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
          for (int k=0;k<3;k++)
            for (int t=0;t<3;t++)
              if (!(t!=0&&k!=0&&k==t))
                f[l][r][i][j]=(f[l][r][i][j]+f[l][m[l]][i][k]*f[m[l]+1][r][t][j])%mod; //*
	}
}

int main(){
	cin>>s; n=s.length();
	for (i=0;i<n;i++)
	  if (s[i]=='('){
	  	int cnt=1;
	  	for (j=i+1;j<n;j++){
	  	  if (s[j]=='(') cnt++; else cnt--;
	  	  if (cnt==0) break;
		}
		m[i]=j;
	  }
	dp(0,n-1);
	ll ans=0;
	for (i=0;i<3;i++)
	  for (j=0;j<3;j++) ans=(ans+f[0][n-1][i][j])%mod;
	cout<<ans<<endl; 
	return 0;
}

  

原文地址:https://www.cnblogs.com/edmunds/p/13693296.html