题意:给定一个只含左右小括号和问号的序列。我们可以改变问号成为小括号,每次改变都有相应的花销,将第i个问号改为左括号花销为a[i],将第i个问号改为右括号花销为b[i]。当最后的序列左右括号个数相等,且对于任意位置左括号的出现次数大于等于右括号则记为合法。求改变成合法序列的最小花销及改变后的字符串。若不能得到合法字符串,输出-1。
题解:贪心。将字符串从左到右扫一遍,遇到左括号就使计数器加1,遇到右括号就使计数器减1,如果是问号就优先改为右括号,并使计数器减1,将b[i]的值加入ans,让该问号改为右括号,且把a[i]-b[i]和位置i作为一个pair加入set。如果计数器变为负数且set不为空,则找出set中的首元素,将a-b的值加入ans,并将字符串该位置i改为左括号。这个操作的实际意义就保证了ans能达到尽量小的值。如果计数器变为负数且set已为空,那么最后怎么改也不能使字符串合法,输出-1直接结束程序即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=50005; 4 int cnt=0; 5 char s[N]; 6 long long a,b,ans=0; 7 set< pair<long long,int> > S; 8 int main() 9 { 10 scanf("%s",s); 11 int len=strlen(s); 12 for (int i=0;i<len;++i) 13 { 14 if (s[i]=='(') ++cnt; 15 else if (s[i]==')') --cnt; 16 else 17 { 18 scanf("%I64d%I64d",&a,&b); 19 ans+=b; s[i]=')'; --cnt; 20 S.insert(make_pair(a-b,i)); 21 } 22 while (cnt<0) 23 { 24 if (S.empty()) return puts("-1"),0; 25 ans+=S.begin()->first; 26 s[S.begin()->second]='('; 27 S.erase(S.begin()); 28 cnt+=2; 29 } 30 } 31 if (cnt) puts("-1"); 32 else printf("%I64d %s ",ans,s); 33 return 0; 34 }