Codeforces Round #712 (Div. 1) A. Balance the Bits

原题链接:

Problem - 1503A - Codeforces

题目描述:

A sequence of brackets is called balanced if one can turn it into a valid math expression by adding characters '+' and '1'. For example, sequences '(())()', '()', and '(()(()))' are balanced, while ')(', '(()', and '(()))(' are not.

You are given a binary string ss of length nn. Construct two balanced bracket sequences aa and bb of length nn such that for all 1≤i≤n1≤i≤n:

  • if si=1si=1, then ai=biai=bi
  • if si=0si=0, then ai≠biai≠bi

If it is impossible, you should report about it.

Input

The first line contains a single integer tt (1≤t≤1041≤t≤104) — the number of test cases.

The first line of each test case contains a single integer nn (2≤n≤2⋅1052≤n≤2⋅105, nn is even).

The next line contains a string ss of length nn, consisting of characters 0 and 1.

The sum of nn across all test cases does not exceed 2⋅1052⋅105.

Output

If such two balanced bracked sequences exist, output "YES" on the first line, otherwise output "NO". You can print each letter in any case (upper or lower).

If the answer is "YES", output the balanced bracket sequences aa and bb satisfying the conditions on the next two lines.

If there are multiple solutions, you may print any.

题目大意:

给定一个二进制字符串s,要求根据字符串s构造两个合法的括号序列a和b。

规则为:当s[i]=’0‘时,a[i]必须等于b[i],当s[i]='1’时,a[i]必须不等于b[i]。

解题思路:

能放左括号就尽量放左括号。我们记左括号为+1,右括号为-1,那么合法的括号序列,整个的和一定为0。

设sum1记录括号序列a,sum2记录括号序列b,从左往右遍历,对于所有的s[i]=1,我们就先假定a[i]=b[i]='('。sum1和sum2都加1.

遇到s[i]=0,若当前sum1>sum2,则给a加右括号,sum1减1,给b加左括号,sum2加1。否则反之。

遍历完毕之后如果sum1和sum2不等于0,则需要调整。我们可以意识到我们只能对s[i]=1的位进行调整。

所以如果此时的sum1不等于sum2,或者sum1和sum2为奇数,则无解。

调整的方式是从右往左遍历,遇到s[i]=1则把a[i]和b[i]都调整为右括号,直到sum1和sum2为0。

代码(CPP):

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3fffffff;
int n, a[maxn], b[maxn];
string s;

/*
    能放左括号就尽量放左括号。我们记左括号为+1,右括号为-1,那么合法的括号序列,整个的和一定为0。
    设sum1记录括号序列a,sum2记录括号序列b,从左往右遍历,对于所有的s[i]=1,我们就先假定a[i]=b[i]='('。sum1和sum2都加1.
    遇到s[i]=0,若当前sum1>sum2,则给a加右括号,sum1减1,给b加左括号,sum2加1。否则反之。
    遍历完毕之后如果sum1和sum2不等于0,则需要调整。我们可以意识到我们只能对s[i]=1的位进行调整。
    所以如果此时的sum1不等于sum2,或者sum1和sum2为奇数,则无解。
    调整的方式是从右往左遍历,遇到s[i]=1则把a[i]和b[i]都调整为右括号,直到sum1和sum2为0。
*/

bool check()
{
    int L1 = 0, R1 = 0, L2 = 0, R2 = 0;
    for (int i = n; i >= 1; i--)
    {
        if(a[i] == 1)
            L1++;
        if(a[i] == 0)
            R1++;
        if(b[i] == 1)
            L2++;
        if (b[i] == 0)
            R2++;
        if(L1 > R1 || L2 > R2)
            return false;
    }
    return true;
}

void print()
{
    for (int i = 1; i <= n; i++)
    {
        if(a[i] == 1)
            cout << "(";
        else
            cout << ")";
    }
    cout << endl;
    for (int i = 1; i <= n; i++)
    {
        if(b[i] == 1)
            cout << "(";
        else
            cout << ")";
    }
    cout << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout << fixed;
    cout.precision(18);

    int t;
    cin >> t;
    while(t--)
    {
        cin >> n;
        cin >> s;
        s = " " + s;
        if(s[1] == '0')
        {
            cout << "NO\n";
            continue;
        }
        int sum1 = 0, sum2 = 0;
        for (int i = 1; i <= n; i++)
        {
            if(s[i] == '1')
                sum1++, sum2++, a[i] = 1, b[i] = 1;
            else
            {
                if(sum1 > sum2)
                    sum1--, sum2++, a[i] = 0, b[i] = 1;
                else
                    sum1++, sum2--, a[i] = 1, b[i] = 0;
            }
        }
        if(sum1 != sum2 || sum1 & 1)
        {
            cout << "NO\n";
            continue;
        }
        for (int i = n; i >= 1; i--)
        {
            if(sum1 == 0)
                break;
            if(s[i] == '1')
                a[i] = 0, b[i] = 0, sum1 -= 2, sum2 -= 2;
        }
        if(check())
        {
            cout << "YES\n";
            print();
        }
        else
            cout << "NO\n";
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值