Codeforces149 D. Coloring Brackets(区间dp,合法括号序列性质)
Posted live4m
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces149 D. Coloring Brackets(区间dp,合法括号序列性质)相关的知识,希望对你有一定的参考价值。
题意:
给定合法括号序列s,现在要给每个位置上色,可以涂红色,蓝色,或者不上色
要求:
1.对于一对匹配的括号,必须而且只能有一个括号被上色
2.相邻位置的颜色不能相同,但是可以都不上色
问整个括号串有多少种上色方案,答案对1e9+7取模
数据范围:|s|<=700
解法:
因为是合法括号序列,那么匹配的括号一定是这样的:
匹配的括号一定是不交叉的,下面是一个非法匹配例子:
区间dp,令d[l,r]为区间[l,r]的合法方案数,因为需要满足相邻位置颜色不同,合并的时候需要考虑相邻颜色,
那么令d[l,r,x,y]为区间[l,r],左端点颜色为x,右端点颜色为y的合法方案数。
因为需要考虑每一对匹配括号的颜色,所以不能将匹配的两端分别放在两个待合并区间,
考虑到匹配边要么是全包含,要么不相交,那么合并的时候可以这样枚举分割线(图中紫色为分割线):
即对于区间[l,r],如果l和r是匹配的,这时候是全包含,那么递归处理[l+1,r-1],
否则找到左端点l的匹配位置p,合并[l,p]和[p+1,r](显然匹配位置p一定在[l,r]中)。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=705;
const int mod=1e9+7;
int d[maxm][maxm][3][3];
char s[maxm];
int R[maxm];
int n;
void dfs(int l,int r)
if(l+1==r)//递归终点
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(i&&j)continue;
if(!i&&!j)continue;
d[l][r][i][j]=1;
return ;
if(R[l]==r)//包含
dfs(l+1,r-1);
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(i&&j)continue;
if(!i&&!j)continue;
for(int x=0;x<3;x++)
for(int y=0;y<3;y++)//l+1和r-1不一定是匹配的
if(i&&x&&i==x)continue;
if(j&&y&&j==y)continue;
d[l][r][i][j]+=d[l+1][r-1][x][y];
d[l][r][i][j]%=mod;
else
int p=R[l];
dfs(l,p),dfs(p+1,r);
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)//l和p不一定匹配
for(int x=0;x<3;x++)
for(int y=0;y<3;y++)//p+1和r不一定匹配
if(j&&x&&j==x)continue;
d[l][r][i][y]+=d[l][p][i][j]*d[p+1][r][x][y]%mod;
d[l][r][i][y]%=mod;
signed main()
scanf("%s",s+1);
n=strlen(s+1);
//
stack<int>stk;
for(int i=1;i<=n;i++)
if(s[i]=='(')stk.push(i);
else R[stk.top()]=i,stk.pop();
//
dfs(1,n);
int ans=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
ans=(ans+d[1][n][i][j])%mod;
cout<<ans<<endl;
return 0;
以上是关于Codeforces149 D. Coloring Brackets(区间dp,合法括号序列性质)的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces149D Coloring Brackets
区间DP Coloring Brackets CodeForces - 149D