题目链接
https://codeforces.ml/contest/1504/problem/C
题目截图
题目大致描述
给定一个01串,判断是否能构造出两个平衡的括号序列ans1和ans2,若能给定其中一种解,构造需满足以下规则:
对于01串中元素为0的位置i,ans1[i] != ans2[i]
对于01串中元素为1的位置i,ans1[i] == ans2[i]
题解
这题是是我在调B调到自闭的时候切的题目。。。比赛时到知道写假了。。。贪心部分贪错了
赛后我看了一下打算暴力搜索。。果真TLE了
于是研究了下出题人的思路,以下便是对出题人的理解(尽管他出的题目我掉了近两百分。。不过该出题人确实有水平。。
首先统计01串中0的数目,若0的数目为奇数显然无法构造,原因如下:
对于01串中的1可以贡献ans1和ans2偶数个'(',对于01串中的0可以贡献ans1和ans2奇数个'(',由于ans1和ans2均为平衡括号序列,故'('个数 == ')'个数,又有n是偶数,故'('数目是偶数,那么0的数目是偶数
其次对于平衡括号序列,首位必须分别为'('和')'因此01串首位必须同时为1
然后大胆猜想,上面的必要条件是不是也是充分条件呢?
事实上出题人提供了一个比较巧妙的构造方法,如下
对于01串中的1显然也是偶数,因此对于前一半1 ans1[i] = ans2[i] = '(',对于后一半1 ans1[i] = ans2[i] = ')',此时1对应的括号是成对存在且匹配
对于01串中的0可以交替赋值'('以及')',可以证明此时ans1和ans2均为平衡括号序列
代码如下
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define IOS std::ios_base::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
using namespace std;
const int maxn = 2e5 + 50;
int t;
int n;
char s[maxn];
int cnt;
char ans1[maxn], ans2[maxn];
signed main() {
IOS
cin >> t;
while(t--) {
cin >> n;
cin >> (s + 1);
cnt = 0;
for(int i = 1;i <= n;++i) {
if(s[i] == '0') { ++cnt; }
}
if(cnt % 2 == 1 || s[1] == '0' || s[n] == '0') {
cout << "NO\n";
continue;
}
int k = 0;
for(int i = 1;i <= n;++i) {
if(s[i] == '1') {
if(2 * k < n - cnt) {
ans1[i] = ans2[i] = '(';
k++;
} else {
ans1[i] = ans2[i] = ')';
k++;
}
}
}
bool flag = true;
for(int i = 1;i <= n;++i) {
if(s[i] == '0') {
if(flag) {
ans1[i] = '(';
ans2[i] = ')';
flag = !flag;
} else {
ans1[i] = ')';
ans2[i] = '(';
flag = !flag;
}
}
}
ans1[n+1] = ans2[n+1] = 0;
cout << "YES\n";
cout << (ans1 + 1) << '\n';
cout << (ans2 + 1) << '\n';
}
return 0;
}