HDU 6299 - Balanced Sequence [2018杭电多校联赛第一场 B](贪心)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6299

【题意】
对于只由’(‘和’)’构成的字符串,定义正规字符串:
1.空串是正规字符串
2.如果A和B是正规字符串,那么A+B也是正规字符串
3.如果A是正规字符串,那么(A)也是正规字符串
现在给n个括号序列,可以对它们任意排列后构成一个括号序列,然后要使得这个序列的一个子序列构成一个正规字符串,问你这个正规字符串的最大长度是多少?

【输入格式】
第一行为数据组数T,接下来每组数据第一行为n(n<=1e5)下面n行每行一个括号序列,每个序列的长度不超过1e5,所有序列长度之和不超过5e6

【输出格式】
每组数据输出一个整数,代表重排之后序列的子序列中最长的正规字符串长度

【思路】
首先题目定义的正规字符串其实就是左右括号相匹配的字符串,问题可以转换成将这n个序列重新排列之后,最多可以消掉多少个’(‘和’)’.我们可以先对每一个字符串用栈进行括号匹配,然后把能消掉的都消掉,消完剩下的字符串只有下面的三种情况
1 (((((…((((( 即若干左括号
2 )))))…))))) 即若干右括号
3 )))..)(…((( 即左边若干个右括号,右边若干个左括号

然后对这些字符串重排,可以肯定的是类型1的字符串全部放到左边,类型2的字符串全部放到右边,关键问题就是类型3的字符串内部怎么进行排列。
首先要把类型3的字符串再细分成两种,一种是类似))((((((((这样左少右多的,一种是类似))))))))((这样左多右少的,左少右多的一定放在左多右少的前面。
然后如果两个字符串全是左少右多的,那么根据左边的)数量从小到大排序
如果两个字符串全是左多右少的,那么根据右边的(数量从大到小排序
至于为什么是这样贪心,我也不会证明,就是在纸上画出来好多个例子慢慢试的…..

#include<bits/stdc++.h>
using namespace std;
const int maxn=5000050;

struct node{
    int a,b;
    node(int aa=0,int bb=0):a(aa),b(bb){}
    bool operator<(const node& e)const{
        if(b>=a && e.b<=e.a) return 0;//前短后长 的放 前长后短 的前面
        if(b<=a && e.b>=e.a) return 1;
        if(b>=a && e.b>=e.a){         //都是 前短后长,前面越小越靠前
            return a>e.a;
        }
        if(b<=a && e.b<=e.a){         //都是 前长后短,后面越大越靠前
            return b<e.b;
        }
    }
};

int n;
char s[maxn];
stack<char> st;
vector<node> vt;

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int ans=0;
        int L=0,R=0;//记最左端的'('个数和最右端的')'个数
        vt.clear();

        for(int i=0;i<n;++i){
            scanf("%s",s);
            int a=0,b=0;
            while(st.size()) st.pop();

            for(int j=0;s[j];++j){
                if('('==s[j]){
                    ++a;
                    st.push(s[j]);
                }
                else {
                    ++b;
                    if(st.size()){
                        st.pop();
                        ++ans;
                        --a;
                        --b;
                    }
                }
            }
            if(b==0) L+=a;
            else if(a==0) R+=b;
            else vt.push_back(node(a,b));
        }
        sort(vt.begin(),vt.end());

        int tmp=L;//记录当前可用的'('个数

        for(int j=0;j<vt.size();++j){
            ans+=min(tmp,vt[j].b);
            if(tmp<=vt[j].b) tmp=0;
            else tmp-=vt[j].b;
            tmp+=vt[j].a;
        }

        ans+=min(tmp,R);

        ans<<=1;
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiao_k666/article/details/81199019