codeforces 149D Coloring Brackets 区间DP

来源:互联网 发布:线切割编程例子 编辑:程序博客网 时间:2024/05/16 05:43

题意:给你一串括号,每个括号可以涂色,蓝色或者红色或者不涂,问你有多少种方案数,其中涂色有些限制。
1.每对括号有且仅有其中一个被涂色。
2.相邻的括号不能涂相同的颜色,但是相邻的括号可以同时不涂色。

那我们怎么做呢。
首先他已经给出了一个合法的括号序列,我们只要找每个左括号右边的第一个右括号就可以了,设dp[l][r][x][y]表示l到r这段区间的答案,l和r的颜色分别为x和y的方案数(0/1/2)。
那么dp有三种转移。
第一种l+1=r时。其实和初始化差不多。
dp[l][r][2][0]=1;
dp[l][r][0][2]=1;
dp[l][r][1][0]=1;
dp[l][r][0][1]=1;
相邻的括号不能都涂色。

第二种,r和l是一对匹配的括号。
这种情况下我们要计算l和r区间内合法的方案,简单来说就是括号套括号。转移如下:
dfs(l+1,r-1);
fo(i,0,2)
fo(j,0,2)
{
if (j!=1)
dp[l][r][0][1]=(dp[l][r][0][1]+dp[l+1][r-1][i][j])%mo;
if (i!=1)
dp[l][r][1][0]=(dp[l][r][1][0]+dp[l+1][r-1][i][j])%mo;
if (j!=2)
dp[l][r][0][2]=(dp[l][r][0][2]+dp[l+1][r-1][i][j])%mo;
if (i!=2)
dp[l][r][2][0]=(dp[l][r][2][0]+dp[l+1][r-1][i][j])%mo;
}
这个自己推一推都能知道。
第三种:普通情况,l和r没什么关系,这种情况其实就是矩阵连乘。。。
设mid表示和l匹配的那个括号。
dp[l][r][i][j]+=dp[l][mid][i][x]*dp[mid+1][r][y][j];

然后整个dp过程是用搜索完成的。。

#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long ll;const int N=1e3;const int mo=1e9+7;const int inf=1e9;int dp[N][N][3][3],a[N],match[N],b[N];    char s[N];int tot,len;inline void get(){    int tot=0;    fo(i,0,len-1)    {        if (s[i]=='(')b[tot++]=i;        else         {            match[i]=b[tot-1];            match[b[tot-1]]=i;            tot--;        }    }}inline void dfs(int l,int r){    if (l+1==r)    {        dp[l][r][2][0]=1;        dp[l][r][0][2]=1;        dp[l][r][1][0]=1;        dp[l][r][0][1]=1;        return;    }    else if (match[l]==r)    {        dfs(l+1,r-1);        fo(i,0,2)            fo(j,0,2)            {                if (j!=1)                dp[l][r][0][1]=(dp[l][r][0][1]+dp[l+1][r-1][i][j])%mo;                if (i!=1)                dp[l][r][1][0]=(dp[l][r][1][0]+dp[l+1][r-1][i][j])%mo;                if (j!=2)                dp[l][r][0][2]=(dp[l][r][0][2]+dp[l+1][r-1][i][j])%mo;                if (i!=2)                dp[l][r][2][0]=(dp[l][r][2][0]+dp[l+1][r-1][i][j])%mo;            }            return;    }    else     {        int nu=match[l];        dfs(l,nu);        dfs(nu+1,r);        fo(i,0,2)        {            fo(j,0,2)            {                fo(x,0,2)                {                    fo(y,0,2)                    {                        if (!(x==1&&y==1 || x==2&&y==2))                        dp[l][r][i][j]=(dp[l][r][i][j]+dp[l][nu][i][x]*dp[nu+1][r][y][j])%mo;                    }                }            }        }    }}int main(){    while(scanf("%s",s)!=EOF)    {        len=strlen(s);        memset(dp,0,sizeof(dp));        get();        dfs(0,len-1);        ll ans=0;        fo(i,0,2)        fo(j,0,2)        ans=(ans+dp[0][len-1][i][j])%mo;        printf("%lld\n",ans);    }}
0 0