您的位置:首页 > 其它

codeforces 149D Coloring Brackets 区间DP

2017-02-18 16:56 627 查看
题意:给你一串括号,每个括号可以涂色,蓝色或者红色或者不涂,问你有多少种方案数,其中涂色有些限制。

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

[3][3],a
,match
,b
;
char s
;
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;
4000

printf("%lld\n",ans);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces dp