区间DP Coloring Brackets CodeForces - 149D
Posted Vincent_0000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间DP Coloring Brackets CodeForces - 149D相关的知识,希望对你有一定的参考价值。
题目来源
反思
这个题目只对了5个数据点,主要的原因在与题目没有理解透彻,不能用一般的区间DP思想去解决这个题目。
以后做题目不能只注意题目表面的意义,还要多提炼题目内层含义!
以后还是读英文原题,多提高自己的阅读能力,对题目的理解也会更深刻一些。
题解
- 提取题目限制条件
① 每个字符有三种情况:不染色,染成红色,染成蓝色
② 每对匹配的括号,有且仅有一个字符被染色
③ 所有相邻的两个字符,不能染成同一种颜色
④ 每对字符串是固定的并且是合法的(我错在这个地方,直接哭死😭)
- 题目类型分析
题目要求求方案数,那么首先就要想到DP,DP的三大判断嘛,最大最小值以及方案数。
括号问题,涉及到区间DP,而且有颜色状态。
那么初步分析之后,尝试使用区间DP + 状态机的思想方式去做这个题目。
- DP分析
因为猜测考点为区间+状态机,所以状态集合设置为四维:
f
(
l
,
r
,
a
,
,
b
)
f(l, r, a, ,b)
f(l,r,a,,b)。
表示为:在区间
(
l
,
r
)
(l ,r)
(l,r)中,
l
l
l点对应颜色状态为
a
a
a,
r
r
r点对应颜色状态为
b
b
b的所有方案数。
a
,
b
∈
[
0
,
2
]
a, b \\in [0, 2]
a,b∈[0,2] 0代表无颜色,1代表红,2代表蓝。
状态划分:
可分为两种情况:①l点对应的右括号在r点 ② l点对应的右括号不在r点,在k点。
对于第一种情况:状态转移对应内外组合,也就是他的状态转移是内部+外部的。
状态转移方程为:
f
[
l
]
[
r
]
[
a
]
[
b
]
=
m
o
d
(
f
[
l
]
[
r
]
[
a
]
[
b
]
+
f
[
l
+
1
]
[
r
−
1
]
[
c
]
[
d
]
)
f[l][r][a][b] = mod(f[l][r][a][b] + f[l + 1][r - 1][c][d])
f[l][r][a][b]=mod(f[l][r][a][b]+f[l+1][r−1][c][d])
这里我们需要注意的是
(
a
,
b
)
(a, b)
(a,b)对应的括号,染色的时候有且仅有一种颜色,而内部的
(
c
,
d
)
(c, d)
(c,d)对应的括号就可以随意一点,因为无论哪一种情况都可以得到(第二种情况都包含了),需要保证的是
a
,
c
a, c
a,c 或者
d
,
b
d, b
d,b不能染上相同的颜色。
对于第二种情况:状态转移对应左右组合。状态转移是左区间+右区间。
状态转移方程为:
f
[
l
]
[
r
]
[
a
]
[
d
]
=
m
o
d
(
f
[
l
]
[
r
]
[
a
]
[
d
]
+
m
o
d
(
f
[
l
]
[
k
]
[
a
]
[
b
]
∗
f
[
k
+
1
]
[
r
]
[
c
]
[
d
]
)
)
f[l][r][a][d] = mod(f[l][r][a][d] + mod(f[l][k][a][b] * f[k + 1][r][c][d]))
f[l][r][a][d]=mod(f[l][r][a][d]+mod(f[l][k][a][b]∗f[k+1][r][c][d]))
同理:我们需要注意
(
a
,
b
)
(a, b)
(a,b)对应的括号,染色的时候有且仅有一种颜色,而内部的
(
c
,
d
)
(c, d)
(c,d)对应的括号颜色任意,需要保证的是
b
,
c
b, c
b,c不能染上相同的颜色。
这两个地方需要注意的细节我都踩坑了😓,不知道自己错哪里的朋友要注意以上这两种情况的细节哦!
因为括号是一一对应的,直接通过枚举的形式感觉比较麻烦,所以使用递归来解决这道题目。
- 边界情况
当区间只有两个数的时候,符合条件的情况设置为1。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rep(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << endl
#define mod(x) (x) % MOD
#define ENDL "\\n"
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 700 + 7, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
char s[N];
int R[N], n;
ll f[N][N][3][3], ans;
stack<int> stk;
inline bool check(int a, int b){
return (a == b) || (a && b);
}
inline bool judge(int b, int c){
return b == c && b > 0;
}
void dp(int l, int r){
if (l + 1 == r){
_for (a, 0, 2) _for(b, 0, 2) {
if (check(a, b)) continue;
f[l][r][a][b] = 1;
}
return;
}
int k = R[l];
if (k == r){
dp(l + 1, r - 1);
_for (a, 0, 2) _for(b, 0, 2) {
if (check(a, b)) continue;
_for (c, 0, 2) _for (d, 0, 2) {
if (judge(a, c) || judge(d, b)) continue;
f[l][r][a][b] = mod(f[l][r][a][b] + f[l + 1][r - 1][c][d]);
}
}
}
else{
dp(l, k), dp(k + 1, r);
_for (a, 0, 2) _for(b, 0, 2){
if (check(a, b)) continue;
_for(c, 0, 2) _for(d, 0, 2){
if (judge(b, c)) continue;
f[l][r][a][d] = mod(f[l][r][a][d] + mod(f[l][k][a][b] * f[k + 1][r][c][d]));
}
}
}
}
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cout.tie(0), cin.tie(0);
cin >> s + 1;
n = strlen(s + 1);
_for (i, 1, n) if (s[i] == '(') stk.push(i);
else {
R[stk.top()] = i;
stk.pop();
}
dp(1, n);
_for(a, 0, 2) _for(b, 0, 2) ans = mod(ans + f[1][n][a][b]);
cout << ans << ENDL;
return 0;
}
以上是关于区间DP Coloring Brackets CodeForces - 149D的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #106 (Div. 2) Coloring Brackets(区间DP)
Codeforces149 D. Coloring Brackets(区间dp,合法括号序列性质)
CodeForces 149D Coloring Brackets