CF149D Coloring Brackets 题解

本文解析了CF149D Colorful Brackets问题,介绍了如何使用区间动态规划(dp)结合记忆化搜索来解决配对括号的染色问题。关键步骤包括处理配对和非配对情况,以及如何确保合法染色方案数的计算。通过实例和代码展示了如何应用这些技术来计算满足条件的染色方案数,并对1e9+7取模。
摘要由CSDN通过智能技术生成

CF149D Coloring Brackets 题解

题目链接:CF149D Coloring Brackets

题意:给出一个配对的括号序列(如 “ (())() \texttt{(())()} (())()”、“ () \texttt{()} ()” 等,“ )() \texttt{)()} )()”、“ (() \texttt{(()} (()”是不符合要求的),对该序列按照以下方法染色。

  1. 一个括号可以染成红色、蓝色或者不染色。
  2. 一对匹配的括号需要且只能将其中一个染色。
  3. 相邻两个括号颜色不能相同(但都可以不染色)。

求符合条件的染色方案数,对 1000000007 1000000007 1000000007 取模。

容易发现这个题目就是个区间dp

但是仅仅用 d p [ l ] [ r ] dp[l][r] dp[l][r] 并不能表示出两侧括号的颜色

因此设 d p [ l ] [ r ] [ i ] [ j ] dp[l][r][i][j] dp[l][r][i][j] 为区间 [ l , r ] [l,r] [l,r] 内且左右两侧的颜色分别为 i , j i,j i,j 时的方案数 (0为不染色,1为红,2为蓝)

考虑边界:当 l + 1 = r l+1=r l+1=r 时,有
() \text{()} ()

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

一般地,

l l l r r r 配对时,有
( … ) \text{(}\dots\text{)} ()

for(int i=0; i<=2; i++)
    for(int j=0; j<=2; 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;
    }

l l l r r r 不配对时,有
( … ) … ( … ) \text{(}\dots\text{)}\dots\text{(}\dots\text{)} ()()
以及
( … )( … ) \text{(}\dots\text{)}\text{(}\dots\text{)} ()()
等情况,不过本质上是一样的

for(int i=0; i<=2; i++)
    for(int j=0; j<=2; j++)
        for(int p=0; p<=2; p++)
            for(int q=0; q<=2; q++)
            {
                if(j==1&&p==1||j==2&&p==2)continue;
                dp[l][r][i][q]=(dp[l][r][i][q]+dp[l][mch[l]][i][j]*dp[mch[l]+1][r][p][q]%mod)%mod;
            }

值得注意的是,本题并不适用一般的dp顺序,而是采用记忆化搜索

因为本题要求配对的括号有且仅有一个被染色,而一般的顺序难以保证配对的括号在同一个区间内,即不能保证转移中用到的序列都是合法的,因此较为麻烦

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(705)
const int mod=1e9+7;
char a[N];
int n,mch[N],stk[N],top,dp[N][N][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;
    else if(mch[l]==r)
    {
        dfs(l+1,r-1);
        for(int i=0; i<=2; i++)
            for(int j=0; j<=2; 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;
            }
    }else
    {
        dfs(l,mch[l]);dfs(mch[l]+1,r);
        for(int i=0; i<=2; i++)
            for(int j=0; j<=2; j++)
                for(int p=0; p<=2; p++)
                    for(int q=0; q<=2; q++)
                    {
                        if(j==1&&p==1||j==2&&p==2)continue;
                        dp[l][r][i][q]=(dp[l][r][i][q]+dp[l][mch[l]][i][j]*dp[mch[l]+1][r][p][q]%mod)%mod;
                    }
                        
    }
}
signed main()
{
    scanf("%s",(a+1));
    n=strlen(a+1);
    for(int i=1; i<=n; i++)
    {
        if(a[i]=='(')stk[++top]=i;
        else mch[stk[top]]=i,mch[i]=stk[top],--top;
    }
    dfs(1,n);
    int ans=0;
    for(int i=0; i<=2; i++)
        for(int j=0; j<=2; j++)
            ans=(ans+dp[1][n][i][j])%mod;
    printf("%lld\n",ans);
    return 0;
}

本文很多地方参考了这篇文章,写的非常好 ✅ ✅

转载请说明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值