【链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6299
【题意】
排列n个字串的顺序,使得所有字符串连接的括号匹配数最大
n (1e5) s(1e5)
【分析】
观察数据范围,确定dp(nlogn)或者贪心,dp好像不行,试试贪心。。
发现题目的一些特点:
一个串如果内部是匹配的 ,那么肯定内部的匹配对于后面的贡献更大,所以相当于可以删掉这个内部的配对括号。对于所有的串执行这样的预处理后,可以得到三种形式:((((,)))))或者))(((((,那么我们为了最大化匹配数,把所有的(((累计放在左边,所有的)))累计放在右边,那么我们只需要排序中间的左右括号都有的串的顺序来最大化匹配数。
我们定义 L1,R1L1,R1 L2,R2L2,R2 分别为两个串的左括号数量和右括号数量
假如 1 放在 2前面 那么对答案的贡献是 min(R1,L2)min(R1,L2)
扫描二维码关注公众号,回复:
3038467 查看本文章
假如 1 放在 2 后面 那么对答案的贡献是 min(R2,L1)min(R2,L1)
比较对答案的贡献,哪个答案贡献大,选哪种放置方式
如果读答案的贡献一样大,那么我们让左括号多的放前面 因为这样对后面的答案贡献大
【代码】
#include<cstdio>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 6;
int a[maxn];
char s[maxn];
struct node {
int l, r;
bool operator <(const node &h)const {
int t1 = min(l, h.r);
int t2 = min(r, h.l);
return t1 > t2 || (t1 == t2 && (l > h.l));
}
}k[maxn];
int cnt = 0;
int main() {
int t;
scanf("%d", &t);
while (t--) {
cnt = 0;
int n;
scanf("%d", &n);
int L = 0, R = 0;
int ans = 0;
for (int i = 1; i <= n; i++) {
scanf("%s", s);
int len = strlen(s);
int LL = 0;
int RR = 0;
for (int j = 0; j < len; j++) {
if (s[j] == '(') {
LL++;
}
else {
if (LL) {
LL--;
ans += 2;
}
else {
RR++;
}
}
}
if (RR&&LL) {
k[++cnt].l = LL;
k[cnt].r = RR;
}
else if(RR){
R += RR;
}
else L += LL;
}
sort(k + 1, k + 1 + cnt);
for (int i = 1; i <= cnt; i++) {
int LL = k[i].l;
int RR = k[i].r;
ans += min(L, RR)*2;
L -= min(L, RR);
L += LL;
}
ans += min(L, R) * 2;
printf("%d\n", ans);
}
}