传送门
题意
给你一个\(01\)串s, 问是否可以构造两个合法括号串, 使得在s为1的位置两串相同, 为0则不同
输出方案或无解
题解
首先第一个或者最后一个为0显然无解
一个结论是如果只有奇数个0也无解
证明不难
之后在写一堆特判之后, 您会发现: 除此以外均有解
那么第一个一定是\((\), 最后一个一定是\()\)
我们考虑0的部分, 我们把它们单独抽出来, 称之为0串。
一种感性的思路是, 我们要让它反过来之后影响最小, 最好自生自灭
那么我们这样构造, \(()()()()()....\)
反过来之后, 变成 \()()()()(\)
我们只需要外面有一个( 和 ) 修复一下就合法了,
这没问题,直接用第一个和最后一个即可
所以做法就是:
第一个是\((\), 最后一个是\()\)
把0串部分依次填入, 构造\(()()()()\)
然后1串剩下的想怎么填怎么填,合法即可
仔细想想看, 没问题
Impl
#include <iostream>
#include <cstdio>
using namespace std;
int read(){
int num=0, flag=1; char c=getchar();
while(!isdigit(c) && c!='-') c=getchar();
if(c == '-') c=getchar(), flag=-1;
while(isdigit(c)) num=num*10+c-'0', c=getchar();
return num*flag;
}
const int N = 290005;
int T, n;
int a[N], s[N], t[N];
char readc(){
char c=getchar(); while(c!='0' && c!='1') c=getchar();
return c-'0';
};
int main(){
T = read();
while(T--){
n = read();
for(int i=1; i<=n; i++) a[i]=readc();
int n0 = 0; for(int i=1; i<=n; i++) if(!a[i]) n0++;
if(n0 % 2) {
printf("NO\n");
continue;
}
if(!a[1] || !a[n]){
printf("NO\n");
continue;
}
for(int i=1, j=1; i<=n; i++){
if(!a[i]){
s[i]=j%2;
j++;
}
}
int n1=n-n0;
for(int i=1, j=1; i<=n; i++){
if(a[i]){
s[i] = j<=n1/2?1:0;j++;
}
}
for(int i=1; i<=n; i++) t[i] = a[i]?s[i]:(!s[i]);
{
printf("YES\n");
for(int i=1; i<=n; i++) printf("%c", s[i]?'(':')');
printf("\n");
for(int i=1; i<=n; i++) printf("%c", t[i]?'(':')');
printf("\n");
}
}
return 0;
}