2018 Multi-University Training Contest 1-B-Balanced Sequence

(一)题面:

Problem Description

Chiaki has n strings s1,s2,…,sn consisting of '(' and ')'. A string of this type is said to be balanced:

+ if it is the empty string
+ if A and B are balanced, AB is balanced,
+ if A is balanced, (A) is balanced.

Chiaki can reorder the strings and then concatenate them get a new string t. Let f(t) be the length of the longest balanced subsequence (not necessary continuous) of t. Chiaki would like to know the maximum value of f(t) for all possible t.

 

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤1e5) -- the number of strings.
Each of the next n lines contains a string si (1≤|si|≤105) consisting of `(' and `)'.
It is guaranteed that the sum of all |si| does not exceeds 5e6.

 

Output

For each test case, output an integer denoting the answer.

 

Sample Input

2
1
)()(()(
2
)
)(

 

Sample Output

4 2

 

(二)题意:

给定n个只由左右括号组成的字符串,当左括号与右括号匹配时,该字符的权值+2,问:将这n个字符串任意顺序拼接后得到的字符串的权值的最大值是多少。

 

(三)题解:

①对于每一个字符串,在拼接以后进行匹配和在之前进行匹配得到的结果是一致的,于是我们首先可以将每个字符串内部能匹配的括号全部匹配掉,最后可以得到一个类似于“)))(((”的字符串。

②然后问题就转化为了:将多个上述类型字符串进行的重排,使能匹配的括号的数目最大。

③然后就贪心地求解,下面给出一种贪心策略(正确性证明无):

Ⅰ)假设有字符串A和B,枚举两个顺序取较大者,即若A放在B的前面能得到的匹配数目大于B放在A前面的情况,那么就把A放在B前面,反之则反之。

Ⅱ)若两个顺序得到匹配数目相等,那么就比较两个字符串前面部分和后面部分的长度,前面部分比较长的自然放到前面,后面部分比较长的就放到后面,具体细节见代码。

 

(四)代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<stack>
#include<algorithm>
const int maxn=1e6+10;
using namespace std;
char s[maxn];
stack<char>S;
struct Str{
    int f,s;
    Str(){}
    Str(int _f,int _s){f=_f;s=_s;}
    bool operator < (const Str s1)const{
//        if(f >= s && s1.f < s1.s)     //流水线排序
//			return false;
//		if(f < s && s1.f >= s1.s)
//			return true;
//		if(f >= s && s1.f >= s1.s)
//			return s > s1.s;
//		return f < s1.f;
        if(min(f,s1.s)<min(s,s1.f))return 1;
        if(min(f,s1.s)>min(s,s1.f))return 0;
        if(max(f,s1.f)>max(s,s1.s))return f>s1.s?0:1;
                                   return s>s1.f?1:0;
    }
}str[maxn];
Str deal(char *ch,int &ans){
    int f=0,s=0,len=strlen(ch);
    for(int i=0;i<len;i++){
        if(!S.empty()&&(ch[i]==')'&&S.top()=='('))S.pop(),ans++;
        else S.push(ch[i]);
    }
    while(!S.empty()){
        f+=S.top()==')';
        s+=S.top()=='(';
        S.pop();
    }
    return Str(f,s);
}
int main(){
//    freopen("in.txt","r",stdin);
    int T,n;
    scanf("%d",&T);
    while(T--){
        int ans=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%s",s);
            str[i]=deal(s,ans);
        }
        sort(str,str+n);
        int x=str[0].s;
        for(int i=1;i<n;i++){
            if(x==0)x=str[i].s;
            else if(str[i].f<=x)ans+=str[i].f,x=x-str[i].f+str[i].s;
            else if(str[i].f>x)ans+=x,x=str[i].s;
        }
        printf("%d\n",ans*2);
    }
    return 0;
}

 

(五)总结:

赛场上看了这个题,感觉做不了,实际上也确实想不到可以贪心做。

看别人的讨论说贪心的策略是一种流水线排序(注释),可能我那样排本质上是一样的吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值