题解 CF3D 【Least Cost Bracket Sequence】

用堆来实现贪心


读入字符串序列 s1,为了操作方便,我们把这个序列备份至 s2 。

扫描字符串序列 s1 ,统计左括号和右括号的个数,如果遇到? , 先统一化成右括号,并保存在 s2 。

贪 心 开 始。重新扫描 s2,统计左括号右括号的个数,如果当前情况下右括号数比左括号数大,说明没有匹配好,那么我们需要从前面找一个花费最小的?来替换。考虑替换的代价,因为原来默认化成),要想化成(,需要花费\(a[i]-b[i]\)的代价,那么我们就可以用小根堆实现找出价值最小的?,替换成(,并保存在 s2 中。

最后再扫描 s2 ,统计?改成左右括号的代价和,输出答案,同时 s2 ,就是可行的答案。

最后分析一下-1的情况:

  1. 原字符串开头是)或结尾是(,肯定没法找到另一半,无解。
  2. ?的个数比左右括号个数差的绝对值小,无解。
  3. 在贪心过后发现左右括号数不匹配,即出现奇偶数矛盾关系,无解

(其实还有一个点,因为c++默认的priority_queue是大根堆,所以存的时候存负数即\(b[i]-a[i]\),免去重载运算符的麻烦 (人类的本质)

#include<bits/stdc++.h>
#define int long long
#define pi pair<int,int>
#define F first
#define S second
#define mp make_pair
#define ed; puts("-1");return 0;//懒惰直接结束
using namespace std;
string s1,s2;
int l,r,a[50004],b[50004],ans;
priority_queue<pi> q;
signed main() {
	cin>>s1;
	s2=s1;
	int len1=s1.size(),len2=0,sum=0;
	if(s1[0]==')'||s1[len1-1]=='(') {
		ed;
	}
	for(int i=0;i<len1;i++) {
		if(s1[i]=='(') ++l;
		else if(s1[i]==')') ++r;
		else {
			s2[i]=')';
			cin>>a[i]>>b[i];
			++sum;
		}
	}
	if(l-r>sum||r-l>sum) {
		ed;
	} 
	l=r=0;
	if(s1[0]=='?') s2[0]='(';
	++l;
	for(int i=1;i<s2.size();i++) {
		if(s1[i]=='?') q.push(mp(b[i]-a[i],i));
		if(s2[i]=='(') l++;
		else if(s2[i]==')') r++;
		if(r>l) {
			s2[q.top().S]='(';
			--r;
			++l;
			q.pop();
		}
	}
	if(r-l) {
		ed;
	}
	for(int i=0;i<s2.size();i++) {
		if(s1[i]=='?') {
			if(s2[i]=='(') ans+=a[i];
			else ans+=b[i];
		}
	}
	cout<<ans<<endl;
	cout<<s2;
	return 0;
}
posted @ 2020-04-17 11:16  ahawzlc  阅读(162)  评论(0编辑  收藏  举报