题解:CF2143E Make Good
Welcome24ever · · 题解
首先非常显然,当
遇到这种,操作无限次的题目,一个非常常见且好用的切入点是,观察操作中的不变量。
那么在这个题里什么是没有改变的呢?我们观察这个操作的本质,我们每次操作都是改变了一个
我们发现每次翻转,都会使得奇数位和偶数位同时多一个或少一个左括号。也就是说在这个题中,操作的不变量是奇数位和偶数位左括号数量的差值,我们记一个字符串
下一步我们需要分析,什么样的字符串才是可构造的。首先对于一个合法的括号序列来说,第一个位置必须是左括号,最后一个位置一定是右括号。我们记
因此对于一个合法的 () 组成的,这时候
同时还存在一个约束,就是
因此我们能构造出合法串的条件是:
接下来我们只需要考虑最后的答案如何构造就好了,我们考虑构造一个形如这样的最终答案:
形如这样的字符串肯定是合法的,问题是
- 当
k 为偶数,\text{cnt}(t) = m - k 。 - 当
k 为奇数,\text{cnt}(t) = k - m + 1 。
于是当我们知道了
- 当
\text{cnt}(t)\geq 0 ,取偶数k = m - \text{cnt}(t) 。 - 当
cnt(t) < 0 ,取奇数k = \text{cnt}(t) + m -1 。
有了
// 再次鼓起丧失的勇气。
#include<bits/stdc++.h>
using namespace std;
const int Welcome24ever = 0;
#define endl '\n'
#define int long long
typedef pair<int, int> PII;
void IHaveNoLimitation() {
int n;
string str;
cin >> n >> str;
if (n & 1) {
cout << -1 << endl;
return;
}
int m = n / 2;
int cnt = 0;
for (int i = 0; i < n; ++i) {
if (str[i] == '(') {
if (i & 1) cnt--;
else cnt++;
}
}
if (cnt < 2 - m || cnt > m || ((cnt - m) & 1)) {
cout << -1 << endl;
return;
}
int tmp;
if (cnt >= 0) tmp = m - cnt;
else tmp = cnt + m - 1;
string ans;
for (int i = 0; i < tmp; i++) ans += '(';
for (int i = 0; i < m - tmp; ++i) ans += "()";
for (int i = 0; i < tmp; i++) ans += ')';
cout << ans << endl;
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
IHaveNoLimitation();
}
return Welcome24ever;
}