CodeForces - 149D(区间DP)

题意:给你一个完整的括号匹配让你涂色,涂色的条件是

一个括号必须涂一边,而且只能涂一边。相邻的颜色不能相同而且只能涂蓝色和红色,然后求涂色方案数

题解:用思维然后dp[l][r][lc][rc]表示我此时涂的是第l到第r个括号边,lc表示之前左边涂的颜色,rc表示之前右边涂的颜色,0表示没涂,1表示涂蓝,2表示涂红色

然后判断l和r是在同一个括号,两个相邻的括号,两个括号不相邻的这些情况怎么转移一下即可


#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
typedef long long int ll;
const int mod = 1e9+7;
const int mx = 705;
ll dp[mx][mx][3][3];
char s[mx];
int p[mx];
stack<int>st;
ll dfs(int l,int r,int lc,int rc){
    if(l>=r)    return 1;
    if(dp[l][r][lc][rc]!=-1)    return dp[l][r][lc][rc];
    int x = p[l];
    int y = p[r];
    dp[l][r][lc][rc] = 0;
    if(x==r){
        for(int i = 1; i <= 2; i++)
            if(i!=rc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,r-1,0,i))%mod;
        for(int i = 1; i <= 2; i++)
            if(i!=lc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,r-1,i,0))%mod;
    }
    else if(x+1==y){
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                if(i!=lc&&j!=rc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,i,0)*dfs(y+1,r-1,0,j))%mod;
        for(int i = 1;  i<= 2; i++)
            for(int j = 1;  j <= 2; j++)
                if(i!=j)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,0,i)*dfs(y+1,r-1,j,0))%mod;
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                if(i!=lc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,i,0)*dfs(y+1,r-1,j,0))%mod;
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                if(j!=rc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,0,i)*dfs(y+1,r-1,0,j))%mod;
    }
    else{
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                if(i!=lc&&j!=rc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,i,0)*dfs(x+1,y-1,0,0)%mod*dfs(y+1,r-1,0,j))%mod;
        for(int i = 1;  i<= 2; i++)
            for(int j = 1;  j <= 2; j++)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,0,i)*dfs(x+1,y-1,i,j)%mod*dfs(y+1,r-1,j,0))%mod;
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                if(i!=lc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,i,0)*dfs(x+1,y-1,0,j)%mod*dfs(y+1,r-1,j,0))%mod;
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                if(j!=rc)
                dp[l][r][lc][rc] = (dp[l][r][lc][rc]+dfs(l+1,x-1,0,i)*dfs(x+1,y-1,i,0)%mod*dfs(y+1,r-1,0,j))%mod;
    }
 //   cout<<dp[l][r][lc][rc]<<endl;;
    return dp[l][r][lc][rc];
}
int main(){
    memset(dp,-1,sizeof(dp));
    int n;
    scanf("%s",s+1);
    n = strlen(s+1);
    for(int i = 1; i <= n; i++)
        if(s[i]=='(')
            st.push(i);
        else{
            p[st.top()] = i;
            p[i] = st.top();
            st.pop();
        }
    ll ans = dfs(1,n,0,0);
    printf("%I64d\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值