Balance the Bits(思维+括号序列构造)

98 篇文章 3 订阅

https://codeforces.com/contest/1504/problem/C


觉得大佬讲得很好:引自@mutsuki

合法括号序列也就是无论何时 '('的出现次数次数总≥')'

把括号和括回理解为分数 括号得一分 括回扣一分。目标是使任何时候两个序列的分数都>=0。这么构造可以使两个序列交替加分和扣分,从而满足条件。

而如果原本构造成一个合法,由于有0的存在,必然会导致原来的有一个地方不合法。需要纠正回来那么就要偶数个0.


@https://codeforces.com/profile/drayc

Imagine a 2d plane where (x,y) = (no. of unclosed open brackets in first sequence, no. of unclosed open brackets in second sequence). We can then map the 4 possible moves:

-> adding a '(' to first string when s[i]=1 => we go from x,y to x+1,y+1

-> adding a '(' to first string when s[i]=0 => we go from x,y to x+1,y-1

.. and similarly for adding ')' in both cases, we get opposite moves.

We start at origin, and our objective is to return to the origin after n moves without crossing any of the axes. If you draw it out on paper or something, it will be clear that by following the given strategy, we either stay on the x = y line or x = y + 1 line, and dont cross any of the axes, unless the string begins or ends with a 0.


考虑构造:两端首先要1.

其次将前n/2个1定义为'(',后n/2个1定义为')’;

由于加一分扣一分,那么对于0我们按其出现的奇偶次数分别给予'('/')'

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
char str[maxn];
char p[maxn];
char v[maxn];
int main(void){
   cin.tie(0);std::ios::sync_with_stdio(false);
   LL t;cin>>t;
   while(t--){
       LL len;cin>>len;
       cin>>(str+1);
       LL n=strlen(str+1);
       if((n&1)||(str[1]=='0')||(str[n]=='0')){
          cout<<"NO"<<"\n";
          continue;
       }
       LL cnt=0;
       for(LL i=1;i<=n;i++) if(str[i]=='1') cnt++;
       LL num=1;LL flag=0;
       for(LL i=1;i<=n;i++){
          if(str[i]=='1'&&num<=cnt/2){
             num++;
             v[i]='(';
          }
          else if(str[i]=='1'&&num>cnt/2){
             num++;
             v[i]=')';
          }
          else if(str[i]=='0'&&(!flag)){
             v[i]='(';flag^=1;
          }
          else if(str[i]=='0'&&(flag)){
             v[i]=')';flag^=1;
          }
       }
       for(LL i=1;i<=n;i++){
           if(str[i]=='1') p[i]=v[i];
           else{
              if(v[i]=='(') p[i]=')';
              else if(v[i]==')') p[i]='(';
           }
       }
       stack<char>s;
       for(LL i=1;i<=n;i++){
          if(!s.empty() ){
             if(s.top()=='('&&p[i]==')'){
                s.pop();
             }
             else s.push(p[i]);
          }
          else s.push(p[i]);
       }
       if(!s.empty()){
          cout<<"NO"<<"\n";
       }
       else{
          cout<<"YES"<<"\n";
          for(LL i=1;i<=n;i++){
            cout<<v[i];
          }
          cout<<"\n";
          for(LL i=1;i<=n;i++){
            cout<<p[i];
          }
          cout<<"\n";
       }
   }
   return 0;
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值