贪心+最优策略+栈 7.23杭电多校赛 B

2.

Balanced Sequence

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1432 Accepted Submission(s): 352

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≤105) -- 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 5×106.

Output

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

Sample Input

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

Sample Output

4
2

Source

2018 Multi-University Training Contest 1

Recommend

liuyiding | We have carefully selected several similar problems for you: 6308 6307 6306 6305 6304

题目大意:

​ 已知n个由'(',')'组成的字符串,问把它们按任意顺序连接后的字符串中有多少个()。

想法:

​ 单个字符串内有几个()用栈来判断就好了(像求波兰表达式)。关键是怎么求最优的头尾相连顺序。

思路:

​ 1、剔除字符串内的(),最后会只剩下l个'(',r个‘)’。统计 add=()的个数,l = 剩下的'('个数,r = 剩下的')'个数

​ 2、贪心,最优排序。左多右少在前半部分,右少在前。左少右多在后半部分,左少在前。这样头尾浪费最少,中间匹配最多。

​ 3、计算结果,注意有多种情况。now = 前面剩下的'(' 。now>a[i].l:匹配完后还会剩下,now-=a[i].l,不能now=0。now<a[i].l: 只能匹配now个,然后要now=0

标准题解

对于一个括号序列,令​是长度,​是前缀最小值('(' +1,')'-1),​是最后的和,那么答案就是​。现在这个​和sum都是定值,只要最大化​就好了。每个串,把匹配后的搞掉之后,会得到一个pair (​),表示​个左括号接上​个右括号,把(​)按照一定顺序排一排依次接起来就知道​的最大值了。 ​.

AC代码:

// B
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 101010;
const int MAXS = 101010;
int n;
class Str
{
public:
    int l, r, add;
    bool operator <(const Str &b) const
    {
        if(l >= r && b.l < b.r)     //左多右少在后 
            return false;
        if(l < r && b.l >= b.r)     //左少右多在前 
            return true;        
        if(l >= r && b.l >= b.r)    //右少在前 
            return r > b.r; 
        return l < b.l;             //左少在前 
    }
}a[MAXN];
char s[MAXS];
void solve()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%s", s);
        int len = strlen(s);
        a[i].l = a[i].r = a[i].add = 0;
        for(int j = 0; j < len; j++)
        {
            if(s[j] == '(')
                a[i].r++;
            else
            {
                if(a[i].r > 0)
                    a[i].r--, a[i].add++;  //减1个(,加匹配个数 
                else
                    a[i].l++;
            }
        }
    }
    sort(a + 1, a + n + 1);
    int ans = 0;
    int now = 0;
    for(int i = 1; i <= n; i++)
    {
        if(a[i].l > now)            //可能大于前面的'('数,那也只能匹配那么多 
            a[i].l = now;
        ans += a[i].l + a[i].add;   
        now -= a[i].l;              //减去匹配的以后,可能还剩下'('留给后面的 
        now += a[i].r;
    }
    printf("%d\n", ans * 2);
}
int main()
{
    int T;
    scanf("%d", &T);
    for(int t1 = 1; t1 <= T; t1++)
        solve();
    return 0;
}

参考:

https://www.ideone.com/Wo55gi

猜你喜欢

转载自blog.csdn.net/keeeepgo/article/details/81187176