题解 CF3D 【Least Cost Bracket Sequence】
用堆来实现贪心
读入字符串序列 s1,为了操作方便,我们把这个序列备份至 s2 。
扫描字符串序列 s1 ,统计左括号和右括号的个数,如果遇到?
, 先统一化成右括号,并保存在 s2 。
贪 心 开 始。重新扫描 s2,统计左括号右括号的个数,如果当前情况下右括号数比左括号数大,说明没有匹配好,那么我们需要从前面找一个花费最小的?
来替换。考虑替换的代价,因为原来默认化成)
,要想化成(
,需要花费\(a[i]-b[i]\)的代价,那么我们就可以用小根堆实现找出价值最小的?
,替换成(
,并保存在 s2 中。
最后再扫描 s2 ,统计?
改成左右括号的代价和,输出答案,同时 s2 ,就是可行的答案。
最后分析一下-1
的情况:
- 原字符串开头是
)
或结尾是(
,肯定没法找到另一半,无解。 ?
的个数比左右括号个数差的绝对值小,无解。- 在贪心过后发现左右括号数不匹配,即出现奇偶数矛盾关系,无解
(其实还有一个点,因为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;
}
任何一个伟大的计划,都有一个微不足道的开始