【CodeForces 149D Coloring Barkets】【区间DP/递推】

Problem

传送门

Solution

这道题目很显然是类似于区间DP的,但是状态上要记录最旁边两个的颜色,为什么?因为你要判断更外层染什么颜色。
Tips:
1.除了l+1=r的情况,其他都要枚举所有的颜色可能,因为其他情况最外层两个不一定匹配,颜色可能要枚举,不可能的情况自然是0,中间不会多的。
2.当最外面不匹配时肯定是多个括号并列,用乘法原理计算,我已开始把
int x=match[l],y=x+1;
这句话写成了
int x=match[l],y=match[r];
这样是错的,WA了好几发,因为可能有三个以上的括号并列,这样中间的会漏掉,气死。其实是道水题。
3.我觉得这其实是一道递推题目,以为没有重叠子问题,dp时也没有一般记忆化搜索的判断是否出现过,大家自己思考一下吧。

CODE

/*
 * @key words: DP+dfs
 * @tested on: CF 149D 62ms
 * @Author: LuHaoqi 
 * @Date: 2017-08-11 09:32:01 
 * @Last Modified by: LuHaoqi
 * @Last Modified time: 2017-08-11 09:32:26
 */
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MOD 1000000007

const int MAXN=705;
int f[MAXN][MAXN][3][3],ans=0;
int len,top=0;
int sta[MAXN],match[MAXN];
char str[MAXN];

void ReadInfo()
{
    scanf("%s",str+1);
    len=strlen(str+1);
    for (int i=1;i<=len;i++)
        if (str[i]=='(') sta[++top]=i;
        else match[i]=sta[top],match[sta[top--]]=i;
}
void dp(int l,int r)
{
    if (l+1==r)
    {
        f[l][r][0][1]=f[l][r][1][0]=1;
        f[l][r][0][2]=f[l][r][2][0]=1;
        return;
    }
    if (match[l]==r)
    {
        dp(l+1,r-1);
        for (int x=0;x<3;x++)
            for (int y=0;y<3;y++)
            {
                if (y!=1) 
                    f[l][r][0][1]=(f[l][r][0][1]+f[l+1][r-1][x][y])%MOD;
                if (x!=1) 
                    f[l][r][1][0]=(f[l][r][1][0]+f[l+1][r-1][x][y])%MOD;
                if (y!=2) 
                    f[l][r][0][2]=(f[l][r][0][2]+f[l+1][r-1][x][y])%MOD;
                if (x!=2) 
                    f[l][r][2][0]=(f[l][r][2][0]+f[l+1][r-1][x][y])%MOD;    
            }
        return;
    }
    else
    {
        int x=match[l],y=x+1;
        dp(l,x); dp(y,r);
        for (int i=0;i<3;i++)
            for (int j=0;j<3;j++)
                for (int k=0;k<3;k++)
                    for (int p=0;p<3;p++)
                    {
                        if (j==k && j) continue;//相邻不同色;
                        f[l][r][i][p]+=1LL*f[l][x][i][j]*f[y][r][k][p]%MOD;
                        f[l][r][i][p]%=MOD;
                    }
    }
}
int main()
{
    memset(f,0,sizeof(f));
    ReadInfo();
    dp(1,len);
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            ans=(ans+f[1][len][i][j])%MOD;
    printf("%d\n",ans);
    //system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值