CF1504C Balance the Bits

传送门


题意

给你一个(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
");
             continue;
        }
        
        if(!a[1] || !a[n]){
            printf("NO
");
             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
");
            for(int i=1; i<=n; i++) printf("%c", s[i]?'(':')');
            printf("
");
            for(int i=1; i<=n; i++) printf("%c", t[i]?'(':')');
            printf("
");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ltdjcoder/p/15542102.html