1. 程式人生 > 其它 >hdu6299 2018杭電多校1B Balanced Sequence

hdu6299 2018杭電多校1B Balanced Sequence

技術標籤:思維貪心

題目:

給定 n n n個括號序列,第 i i i個括號序列為 s i s_i si,要將這 n n n個序列重新排個序,然後拼接起來,使拼接成的括號序列的最長括號匹配子序列最長。
( 1 ≤ n ≤ 1 0 5 , ∑ ∣ s i ∣ ≤ 5 ⋅ 1 0 6 ) (1 \le n \le 10^5,\sum |s_i| \le 5 \cdot 10^6) (1n105,si5106)

題解:

首先考慮一個括號序列的最長括號匹配子序列的長度是怎麼算的,設這個括號序列的長度為 n n n,用’(’+1,’)’-1算出的最後的結果為 p r e pre pre

,在這個過程中的字首最小值為 m n mn mn,那麼答案就是 n − p r e + 2 ⋅ min ⁡ ( 0 , m n ) n-pre+2 \cdot \min(0,mn) npre+2min(0,mn)。可以這麼理解,我們要保證整個子序列用’(’+1,’)’-1算出的最後的結果為0且中間的字首最小值大於等於0,那麼首先我們可以刪掉前 − min ⁡ ( 0 , m n ) -\min(0,mn) min(0,mn)個’)’,這樣就可以保證字首最小值大於等於0了,然後左括號多了 p r e − min ⁡ ( 0 , m n ) pre-\min(0,mn) premin(0,mn)個,那麼我們再從右往左將多出來的左括號刪掉就可以了。在這個式子中,我們可以發現 n n
n
p r e pre pre都是固定的,所以只需安排一個順序,使字首最小值最大化即可。把每個括號序列的最終字首和結果和字首最小值搞成一個 p a i r pair pair,可以考慮用氣泡排序式的交換進行貪心,假設前後兩個 p a i r pair pair a , b a,b a,b,那麼假設前面的字首和為 p r e pre pre,那麼我們就要在 min ⁡ ( p r e + a . s e c o n d , p r e + a . f i r s t + b . s e c o n d ) \min(pre+a.second,pre+a.first+b.second) min
(pre+
a.second,pre+a.first+b.second)
min ⁡ ( p r e + b . s e c o n d , p r e + b . f i r s t + a . s e c o n d ) \min(pre+b.second,pre+b.first+a.second) min(pre+b.second,pre+b.first+a.second)中取大的方案,可以發現其中的 p r e pre pre可以提出來然後左右消掉,所以最後比較的就是 min ⁡ ( a . s e c o n d , a . f i r s t + b . s e c o n d ) \min(a.second,a.first+b.second) min(a.second,a.first+b.second) min ⁡ ( b . s e c o n d , b . f i r s t + a . s e c o n d ) \min(b.second,b.first+a.second) min(b.second,b.first+a.second)。但是這樣寫會WA,具體的類似(0,0),(5,4)這樣的 p a i r pair pair,我們應該把(5,4)放前面去,所以當兩個 min ⁡ \min min的結果是一樣的時候,我們把字首和結果大的放前面去,這樣更貪一些(這個點有些玄學)。

複雜度: O ( ∑ ∣ s i ∣ l o g ( ∣ ∑ ∣ s i ∣ ∣ ) ) O(\sum |s_i|log(|\sum|s_i||)) O(silog(si))

程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
//#include<unordered_map>
using namespace std;

#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;
ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int T,n;
string s[maxn];
pii a[maxn];
int cmp(pii a,pii b){
    if(min(a.se,a.fi+b.se)==min(b.se,b.fi+a.se)){
        return a.fi>b.fi;
    }
    return min(a.se,a.fi+b.se)>min(b.se,b.fi+a.se);
}
int main(void){
    // freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>T;
    while(T--){
        cin>>n;
        int sum=0;
        for(int i=1;i<=n;i++){
            cin>>s[i];
            sum+=(int)s[i].length();
            int mn=0,pre=0;
            for(int j=0;j<(int)s[i].length();j++){
                if(s[i][j]=='(')pre++;
                else pre--;
                mn=min(mn,pre);
            }
            a[i].fi=pre;
            a[i].se=mn;
        }
        sort(a+1,a+n+1,cmp);
        int pre=0,mn=INF;
        for(int i=1;i<=n;i++){
            mn=min(mn,pre+a[i].se);
            pre+=a[i].fi;
        }
        cout<<sum-pre+2*min(0,mn)<<endl;
    }
    return 0;
}