CodeForces 149D-Coloring Brackets(区间dp 的好题)

题意:
给一个给定括号序列,给该括号上色,上色有三个要求

1、只有三种上色方案,不上色,上红色,上蓝色

2、每对括号必须只能给其中的一个上色

3、相邻的两个不能上同色,可以都不上色

求0-len-1这一区间内有多少种上色方案

思路:括号匹配问题是典型区间dp问题,这题在此基础上改编增加颜色的规定,于是我需要多定义两层设dp[i][j][l][r]表示:从i到j这个括号序列i位置为l颜色,j位置为r颜色的状态下的总共上色方案。可以规定0为不上色,1为红色,2为蓝色,这样dp[len][len][3][3]状态就定好了。
考虑括号串的匹配过程,都是嵌套的过程,于是我们可以递归的计数,首先得用栈扫一遍串,记载每个左右括号相对的匹配的位置。然后递归的搜索下去。
根据题意的规则,制定搜索的规则。
详见代码:

#include<bits/stdc++.h>
using namespace std;
char s[700+10];
const int mod=1e9+7;
int match[700+10],n;
long long dp[700+10][700+10][3][3];
stack<int>sta;
void init(){
  while(!sta.empty()) sta.pop();
  for(int i=1;i<=n;i++){
    if(s[i]=='(') sta.push(i);
    else { match[i]=sta.top();match[sta.top()]=i;sta.pop();}
  }
}

void dfs(int l,int r){
   if(l+1==r){
     dp[l][r][1][0]=1;dp[l][r][0][1]=1;//每一对括号只有有且只有一个括号有颜色的情况计数,其他为0
     dp[l][r][2][0]=1;dp[l][r][0][2]=1;
     return;
   }
   if(match[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{
     int p=match[l];
     dfs(l,p);dfs(p+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 q=0;q<3;q++){
                  if(k!=q||k==0) dp[l][r][i][j]=(dp[l][r][i][j]+dp[l][p][i][k]*dp[p+1][r][q][j])%mod;//保证相邻的不同颜色,或者都不上色
               }
            }
        }
     }
   }
}

int main(){
   while(~scanf("%s",s+1)){
      n=strlen(s+1);
      init();
      memset(dp,0,sizeof(dp));
      dfs(1,n);
      long long ans=0;
      for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
          ans=(ans+dp[1][n][i][j])%mod;
        }
      }
      printf("%lld\n",ans);
   }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值