SDUT 2022 Winter Individual Contest - A(D)
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDUT 2022 Winter Individual Contest - A(D)相关的知识,希望对你有一定的参考价值。
D - Brackets
链接: link
题意:
给定一个括号序列,现在允许最多反转一段区间,使得 ( ( (变成 ) ) ), ) ) )变成 ( ( (,问这段括号序列在最多可反转一次情况下,能否是合法括号序列
思路:
两重循环枚举需要反转的区间,然后判断反转后,当前这种序列是否合法,针对判断序列合法,有两种判断方法,一种是记忆化搜索,另一种就是区间和+最大最小值判断法
两种方法都需要预处理,
(
(
(视为
1
1
1,
)
)
)视为
−
1
-1
−1
记忆化搜索的话,定义
f
(
p
o
s
,
s
u
m
,
s
t
a
t
e
)
f(pos,sum,state)
f(pos,sum,state)为判断位置到了
p
o
s
pos
pos,
1
−
p
o
s
−
1
1-pos-1
1−pos−1的总和,state为反转的三种状态
0
0
0代表直到当前位置为止,一个都没括号都没反转
1
1
1代表当前这个位置反转了
2
2
2代表前面出现过反转了,后面不会再出现反转
这就相当于枚举反转区间
001122
001122
001122,这样的序列就代表
[
1
,
2
]
[1,2]
[1,2]没反转,
[
3
,
4
]
[3,4]
[3,4]反转,
[
5
,
6
]
[5,6]
[5,6]没反转
这样的话,当遍历完整个序列时,判断序列是否合法,只需要看区间的总和是否为
1
1
1,且区间最小值是否
≥
0
≥0
≥0(在遍历过程中,通过总和是否
<
0
<0
<0来判断,效果一样)
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 5555;
char s[N];
int a[N];
int len;
int dp[N][N][3];
int vis[N][N][3];
bool f(int pos, int sum, int state)
if (sum < 0) return 0;
if (state > 2) return 0;
if (pos == len + 1)
if (sum == 0) return 1;
return 0;
if (vis[pos][sum][state]) return dp[pos][sum][state];
bool now = f(pos, sum, state + 1);
if (state == 0)
now |= f(pos + 1, sum + a[pos], state);
else if (state == 1)
now |= f(pos + 1, sum - a[pos], state);
else
now |= f(pos + 1, sum + a[pos], state);
vis[pos][sum][state] = 1;
return dp[pos][sum][state] = now;
int main()
cin >> s + 1;
len = strlen(s + 1);
for (int i = 1; i <= len; i++)
if (s[i] == '(')
a[i] = 1;
else
a[i] = -1;
if (f(1, 0, 0))
puts("possible");
else
puts("impossible");
第二种方法区间和+最大最小值
先预处理出来区间和,区间最大最小值
然后再枚举反转的区间
假设枚举的区间为
[
l
,
r
]
[l,r]
[l,r]
那么当前区间想要合法的条件是
s
u
m
(
1
,
l
−
1
)
−
s
u
m
(
l
,
r
)
+
s
u
m
(
r
,
n
)
=
0
sum(1,l-1)-sum(l,r)+sum(r,n)=0
sum(1,l−1)−sum(l,r)+sum(r,n)=0首先要保证整段区间的左括号右括号相同,因为是反转,所以带负号
m
i
n
(
1
,
l
−
1
)
≥
0
min(1,l-1)≥0
min(1,l−1)≥0
a
n
d
and
and
s
u
m
(
1
,
l
−
1
)
−
m
a
x
(
l
,
r
)
>
=
0
sum(1,l-1)-max(l,r)>=0
sum(1,l−1)−max(l,r)>=0
a
n
d
and
and
s
u
m
(
1
,
l
−
1
)
−
s
u
m
(
l
,
r
)
+
m
i
n
(
r
+
1
,
n
)
>
=
0
sum(1,l-1)-sum(l,r)+min(r+1,n)>=0
sum(1,l−1)−sum(l,r)+min(r+1,n)>=0
若
m
i
n
v
(
1
,
l
−
1
)
<
0
minv(1,l-1)<0
minv(1,l−1)<0就说明出现了右括号过多的情况,或者左括号还没出现,右括号就出现了,无法匹配的情况,此时无论怎么反转右边的区间都不能合法
若
s
u
m
(
1
,
l
−
1
)
−
m
a
x
(
l
,
r
)
<
0
sum(1,l-1)-max(l,r)<0
sum(1,l−1)−max(l,r)<0,说明在反转后,
[
l
,
r
]
[l,r]
[l,r]过多的左括号无法与弥补左区间的右括号,所以说明反转后
[
1
,
r
]
[1,r]
[1,r]这段区间右括号剩下了,无法匹配的情况
若
s
u
m
(
1
,
l
−
1
)
−
s
u
m
(
l
,
r
)
+
m
i
n
(
r
+
1
,
n
)
<
0
sum(1,l-1)-sum(l,r)+min(r+1,n)<0
sum(1,l−1)−sum(l,r)+min(r+1,n)<0,说明在反转后
[
1
,
n
]
[1,n]
[1,n]这段区间出现了,右括号剩下,无法匹配的现象
只要都满足,说明这段区间在修改后,是合法的
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 5555;
char s[N];
int sum[N][N];
int maxv[N][N], minv[N][N];
int main()
cin >> s + 1;
int len = strlen(s + 1);
for (int i = 1; i <= len; i++)
int all = 0;
int Max = 0, Min = 0;
for (int j = i; j <= len; j++)
if (s[j] == '(')
all++;
else
all--;
sum[i][j] = all;
Max = max(Max, all);
Min = min(Min, all);
maxv[i][j] = Max;
minv[i][j] = Min;
if (sum[1][len] == 0 && minv[1][len] == 0)
puts("possible");
return 0;
else
bool flag = 0;
for (int i = 1; i <= len; i++)
for (int j = i; j <= len; j++)
if (sum[1][i - 1] - sum[i][j] + sum[j + 1][len] != 0)
continue;
if (minv[1][i - 1] < 0 || sum[1][i - 1] - maxv[i][j] < 0 ||
sum[1][i - 1] - sum[i][j] + minv[j + 1][len] < 0)
continue;
flag = 1;
break;
if (flag) break;
if (flag)
puts("possible");
else
puts("impossible");
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激
以上是关于SDUT 2022 Winter Individual Contest - A(D)的主要内容,如果未能解决你的问题,请参考以下文章
SDUT 2022 Winter Team Contest - 1
SDUT 2022 Winter Individual Contest - A(D)
SDUT 2022 Winter Individual Contest - D(K)
SDUT 2022 Winter Individual Contest - D(K)