Codeforces149 D. Coloring Brackets(区间dp,合法括号序列性质)

题意:

给定合法括号序列s,现在要给每个位置上色,可以涂红色,蓝色,或者不上色
要求:
1.对于一对匹配的括号,必须而且只能有一个括号被上色
2.相邻位置的颜色不能相同,但是可以都不上色
问整个括号串有多少种上色方案,答案对1e9+7取模

数据范围:|s|<=700

解法:

因为是合法括号序列,那么匹配的括号一定是这样的:
在这里插入图片描述
匹配的括号一定是不交叉的,下面是一个非法匹配例子:
在这里插入图片描述

区间dp,令d[l,r]为区间[l,r]的合法方案数,因为需要满足相邻位置颜色不同,合并的时候需要考虑相邻颜色,
那么令d[l,r,x,y]为区间[l,r],左端点颜色为x,右端点颜色为y的合法方案数。

因为需要考虑每一对匹配括号的颜色,所以不能将匹配的两端分别放在两个待合并区间,
考虑到匹配边要么是全包含,要么不相交,那么合并的时候可以这样枚举分割线(图中紫色为分割线):
在这里插入图片描述

即对于区间[l,r],如果l和r是匹配的,这时候是全包含,那么递归处理[l+1,r-1],
否则找到左端点l的匹配位置p,合并[l,p]和[p+1,r](显然匹配位置p一定在[l,r]中)。

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=705;
const int mod=1e9+7;
int d[maxm][maxm][3][3];
char s[maxm];
int R[maxm];
int n;
void dfs(int l,int r){
    if(l+1==r){//递归终点
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                if(i&&j)continue;
                if(!i&&!j)continue;
                d[l][r][i][j]=1;
            }
        }
        return ;
    }
    if(R[l]==r){//包含
        dfs(l+1,r-1);
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                if(i&&j)continue;
                if(!i&&!j)continue;
                for(int x=0;x<3;x++){
                    for(int y=0;y<3;y++){//l+1和r-1不一定是匹配的
                        if(i&&x&&i==x)continue;
                        if(j&&y&&j==y)continue;
                        d[l][r][i][j]+=d[l+1][r-1][x][y];
                        d[l][r][i][j]%=mod;
                    }
                }
            }
        }
    }else{
        int p=R[l];
        dfs(l,p),dfs(p+1,r);
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){//l和p不一定匹配
                for(int x=0;x<3;x++){
                    for(int y=0;y<3;y++){//p+1和r不一定匹配
                        if(j&&x&&j==x)continue;
                        d[l][r][i][y]+=d[l][p][i][j]*d[p+1][r][x][y]%mod;
                        d[l][r][i][y]%=mod;
                    }
                }
            }
        }
    }
}
signed main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    //
    stack<int>stk;
    for(int i=1;i<=n;i++){
        if(s[i]=='(')stk.push(i);
        else R[stk.top()]=i,stk.pop();
    }
    //
    dfs(1,n);
    int ans=0;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            ans=(ans+d[1][n][i][j])%mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值