• 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;
    }
    

      

  • 相关阅读:
    Python--__init__方法
    Python--面向对象编程
    用R语言对NIPS会议文档进行聚类分析
    docker oracle install
    java 删除字符串左边空格和右边空格 trimLeft trimRight
    mysql 表名和字段、备注
    docker学习
    shell爬虫
    shell 解析json
    SecureCRT 7.1.1和SecureFx key 亲测可用
  • 原文地址:https://www.cnblogs.com/edmunds/p/13693296.html
Copyright © 2020-2023  润新知