hdu 6299 貪心+分治
阿新 • • 發佈:2019-01-04
題意:
求n個字串任意排列後可以得到的最大的括號匹配個數
解法:
每個字串內部的匹配數是定值,可以讀入的時候處理一下。處理之後得到的是形如")))((("這樣的串,用a和b分別存每個字串剩下的左括號和右括號的個數,這樣字串就可以丟掉,省很多空間。。
可以發現一個貪心的規律:顯然最後應該是 ))((((( + )))(((((( + )))))(( + ))))(( 這樣的形式是最優的,即分成兩個區間,左邊是左括號多的,右邊是右括號多的。而區間內部的順序對於另一個區間是無所謂的,所以只要考慮區間內部最大化匹配數:對於左區間,應該讓右括號多的儘量靠右;對於右區間則相反。
這樣我們定義了一種能得到最優解的偏序關係,將字串按照這個關係排序,統計答案即可。
#include<bits/stdc++.h> using namespace std; #define llp(i,x,y) for(int i=x;i<y;++i) // [x,y) x->y #define rlp(i,x,y) for(int i=y-1;i>=x;--i) // [x,y) y->x #define lp(i,x) for(int i=0;i<x;++i) //[0,x)0->x #define mem(a,x) memset(a,x,sizeof a) typedef long long ll; const ll N=1e5+1000; struct node{ ll a,b; ll ans; bool operator < (node& x){ int tmp1 = a>b; int tmp2 = x.a>x.b; if (tmp1!=tmp2) return tmp1<tmp2; else{ return tmp1==1?b>x.b:a<x.a; } } }Str[N]; char s[N]; void deal(int i){ int len = strlen(s); Str[i].a = Str[i].b = Str[i].ans = 0; llp(k,0,len){ if (s[k] == '(') Str[i].b++; else if (Str[i].b>0) { Str[i].ans+=2; Str[i].b--; } else Str[i].a++; } } int main(){ int t,n; scanf("%d",&t); while(t--){ scanf("%d",&n); lp(i,n) { scanf("%s",s); deal(i); } sort(Str,Str+n);//核心操作 ll ans=0; ll left = 0; lp(i,n){ ans += Str[i].ans + 2*min(left,Str[i].a); left = max(left - Str[i].a,0ll); left += Str[i].b; } printf("%lld\n",ans); } }