ARC141[题解]
\(C\)
注意到一个性质:
- 若 \(P_{2\times i-1} > P_{2\times i}\),那么一定有 \(S_{P_{2\times i - 1}} = (\) 且 \(S_{P_{2\times i}} = )\) 。
- 若 \(Q_{2\times i - 1} < Q_{2\times i}\),那么一定有 \(S_{Q_{2\times i - 1}} = (\) 且 \(S_{Q_{2\times i}} = )\) 。
证明:
首先有一个显然的事实,如果 \(P_{2\times i-1} > P_{2\times i}\) ,那么 \(P_{2\times i-1}\) 和 \(P_{2\times i}\) 一定不能相同,否则交换两者位置,我们可以得到更优的序列。
对于 \(Q\) 同理。
接下来的问题在于,既然两者取不同即可, 为什么规定 \(P_{2\times i-1}\) 一定要是 \((\) 。
首先,对于一个合法的 \(S\) 串,肯定是由合法的括号序列以及合法括号序列的反转组成的。证明可以考虑一个函数 \(f(x)=\sum_{i=1}^{x} A_i\),若 \(S_i=(\) 则 \(A_i = 1\) 否则 \(A_i = -1\)。连接函数图像得到一段连续的曲线,但是当 \(x = 2N\) 时值一定为 \(0\),这是显然的,因为 \(A_i = 1\) 和 \(A_i = -1\) 的数量肯定是相等的。则对于这个图像将其分为两种区间,一种是两个端点值都为 \(0\) 且区间内函数值皆大于等于 \(0\),这是合法的括号序列;另一种是两个端点值都为 \(0\) 且区间内函数值皆小于等于 \(0\),这是合法的括号序列的反转(将 \((\) 变成 \()\),将 \()\) 变成 \((\) ),这是容易理解的。
假设 \(T\) 是 \(S\) 的一个子串。
设 \(L\) 是左括号位置递增的序列,\(R\) 是右括号位置递增的序列。考虑对于 \(T\),\(P\) 和 \(Q\) 分别的取值。
若 \(T\) 是一个合法的括号序列。
显然,\(P\) 的字典序最小的合法取值一定是 \(\{1,2,3,……,2\times N \}\)。
对于 \(Q\),其字典序最大的合法取值一定是 \(\{L_n,R_n,L_{n-1},R_{n-1},……,L_1,R_1 \}\)。首先,对于 \(T\),一定有 \(R_n > L_n\),则我们想让 \(R\) 尽量靠前,但由于要维护其合法,所以放一个左括号才能放右括号。
所以此时对于 \(Q\) 来说,一定有 \(Q_{2\times i-1} <Q_{2\times i}\),且 \(S_{Q_{2\times i-1}}=(\),\(S_{Q_{2\times i}} = )\),所以我们可以根据 \(Q\) 反推出 \(T\)。
若 \(T\) 是一个合法的括号序列的反转。
显然,\(Q\) 的字典序最大的合法取值一定是 \({2\times N,……,3,2,1}\)。
对于 \(P\),其字典序最小的合法取值一定是 \({R_1,L_1,R_2,L_2,……,R_n,L_n}\)。首先,对于反转前的 \(T\),一定有 \(R_n>L_n\),则我们想让 \(L\) 尽量靠前,但反转后 \(L\) 内储存位置对应的左括号都变成了右括号,所以我们要先放 \(R\)。
所以此时对于 \(P\) 来说,一定有 \(P_{2\times i -1} > P_{2\times i}\),且 \(S_{P_{2\times i-1}} = (,S_{P_{2\times i}} = )\) ,所以我们可以根据 \(P\) 反推出 \(T\)。
综上,如果题目给定的 \(P\) 和 \(Q\) 可以被一个存在的括号序列取到,那么其任意一个位置都可以通过 \(P\) 或者 \(Q\) 确定,且满足如上性质。
根据 \(P\) 和 \(Q\) 试着推出答案 \(S\),然后再用 \(S\) 看能不能推出 \(P\) 和 \(Q\),判断掉冲突或者其他无解的情况即可。
\(code\)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w *= -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
int n;
int p[2 * N], q[2 * N];
char ans[2 * N];
vector<int> L, R;
int main()
{
n = read();
for(register int i = 1; i <= 2 * n; i++) p[i] = read();
for(register int i = 1; i <= 2 * n; i++) q[i] = read();
for(register int i = 1; i <= n; i++){
int x = i * 2 - 1, y = i * 2;
if(p[y] < p[x]) ans[p[x]] = '(', ans[p[y]] = ')';
if(q[y] > q[x]) ans[q[x]] = '(', ans[q[y]] = ')';
}
for(register int i = 1; i <= 2 * n; i++){
if(ans[i] == '(') L.push_back(i);
else R.push_back(i);
}
if(L.size() != n || R.size() != n) { puts("-1"); return 0; }
int a = 0, b = 0, res = 0;
for(register int i = 1, u; i <= 2 * n; i++){
if(!res) u = L[a], a++, res++;
else{
if(a < L.size() && L[a] < R[b]) u = L[a], a++, res++;
else if(b < R.size()) u = R[b], b++, res--;
}
if(u != p[i]) { puts("-1"); return 0; }
}
reverse(L.begin(), L.end()), reverse(R.begin(), R.end());
a = 0, b = 0, res = 0;
for(register int i = 1, u; i <= 2 * n; i++){
if(!res) u = L[a], a++, res++;
else{
if(a < L.size() && L[a] > R[b]) u = L[a], a++, res++;
else if(b < R.size()) u = R[b], b++, res--;
}
if(u != q[i]) { puts("-1"); return 0; }
}
for(register int i = 1; i <= 2 * n; i++) printf("%c", ans[i]);
return 0;
}