AT_icpc2014spring_e Parentheses 题解
题目链接:Parentheses
题意:
给定 $n$ 个字符串 $s_1,s_2,\cdots s_n$,每个字符串由括号
(
和)
组成。请问是否可以排列这 $n$ 个字符串,使得这些字符串拼接后是一个合法的字符串。
合法的字符串定义如下:
- 空字符串是合法的。
- 如果 $A$ 和 $B$ 是合法的,那么 $A$ 和 $B$ 拼接后也是合法的。
- 如果 $A$ 是合法的,那么将 $A$ 放在一对匹配的括号内得到的字符串也是合法的。
- 任何其他字符串都是不合法的。
例如,
()()
和(())
是合法的,而())
和((()
是不合法的。输入格式:
输入的第一行包含一个整数 $n~(1 \leq n \leq 100)$,表示字符串的数量。
接下来 $n$ 行,每行包含一个字符串 $s_i~(1 \leq | s_i | \leq 100)$。$s_i$ 中的所有字符都是
(
或)
。输出格式:
如果可以组成一个合法的字符串,则输出一行
Yes
,否则输出No
。
这道题虽然简单,但是坑还是蛮多的。
记 $u_i$ 为字符串 $i$ 的左括号数,$v_i$ 为字符串 $i$ 的右括号数。
考虑将 $u_i > v_i$ 的串按 $v_i$ 顺序排序,将 $v_i \ge u_i$ 的串按 $u_i$ 降序排序。
接着维护一个变量 $S$ ,遍历上面两个数组,每次 $S\gets S-v_i$ 然后 $S\gets S + u_i$ 。
如果第一步操作后 $S<0$ 则无解,操作结束后 $S \ne 0$ 也无解。
时间复杂度 $\mathcal{O}(n\log n)$ ,复杂度瓶颈是排序
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define N ((int)(233))
char s[N]; int cnt1, cnt2;
struct node { int x, y; } a[N], b[N];
void fail() { cout << "No" << '\n'; exit(0); }
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int n; cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> (s + 1); int u = 0, v = 0;
for(int j = 1; s[j]; j++)
if(s[j] == '(') ++u; else { u ? --u : ++v; }
u > v ? a[++cnt1] = {u, v} : b[++cnt2] = {u, v};
}
sort(a + 1, a + 1 + cnt1, [](node a, node b) { return a.y < b.y; });
sort(b + 1, b + 1 + cnt2, [](node a, node b) { return a.x > b.x; });
int sum = 0;
for(int i = 1; i <= cnt1; i++)
if((sum -= a[i].y) < 0) fail(); else sum += a[i].x;
for(int i = 1; i <= cnt2; i++)
if((sum -= b[i].y) < 0) fail(); else sum += b[i].x;
cout << (sum ? "No" : "Yes") << '\n';
return 0;
}
问1:为什么要这么排序?
hack 如下:
4
((
)))
(((
))
问2:为什么要先 $S\gets S-v_i$ ?
hack 如下:
2
)((
))(
问3:$u_i=v_i$ 会影响结果吗?
答:不会。随便放哪个数组,排序后一定在最中间的位置。
题外话:
这次放搞笑图片。