您的位置:首页 > 其它

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

2017-08-11 09:47 387 查看

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