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;
}
posted @ 2022-05-30 19:18  ╰⋛⋋⊱๑落叶๑⊰⋌⋚╯  阅读(76)  评论(0编辑  收藏  举报