题意:给你一个( ? )组成的序列,给出每个?变成(或)的价格,求保证括号匹配的前提下最小的价格是多少,若无法匹配输出-1
分析:
首先对于一个括号的序列
只要对于任意位置,从开头到当前位置的右括号数目≤左括号数目且总左括号数=总右括号数,那么这个序列就是合法的
这个结论也很好证明
()这个显然是满足这个性质的,
而如果将这个合法的序列左右分别加一个左括号和一个右括号也就是(())显然也是符合上述规则的
而多个合法序列并列起来显然也符合上述的性质,
一个合法的序列显然总左括号数=总右括号数,
如果在一个合法序列后面加一个)显然就不合法了,
对应到上面性质也是不符合的
所以得证
既然总的左括号数一定等于总右括号数
那么也就是说?转换成(和)的数目是确定的
那么如果没有别的限制
只需要计算一下所有的x-y中最小的几个作为(,剩下的作为)即可
但每个位置上都有限制
那么我们需要在迫不得已的情况下执行一次类似结尾的处理
这怎么理解呢?
如果我们把到目前为止所有的?都看做)还能保证该地局部的合法(右括号数≤左括号数)
那么也就是说后面无论如何调整,都能保证该位置是合法的
而且我们这里的调整是把?变成的)再变成(
所以已经被处理成合法的位置,
以后无论再怎么处理,都一定也是合法的
所以我们只需要在这种不一定合法的位置,
按照结尾类似的方法,将若干个)变成(直到合法为止即可,或者是说恰好合法,因为剩下还可以变的)可以留到以后再变,而且也一定不会影响当前位置的合法性
所以在过程中一直找最小值,而且不断有新元素加入,可以用优先队列进行贪心
记得开ll
代码:
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; #define ll long long const int maxn=5e4+1; char a[maxn]; struct Node { int val,pos; Node(){} Node(int VAL,int POS){val=VAL,pos=POS;} friend bool operator < (const Node &x,const Node &y) { return x.val>y.val; } }; int main() { int x,y; bool hh=0; scanf("%s",a); int n=strlen(a); int now=0; ll ans=0ll; priority_queue<Node> q; for(int i=0;i<n;i++) { if(a[i]=='(') now++; else if(a[i]==')') now--; else { scanf("%d%d",&x,&y); if(hh) continue; a[i]=')'; ans+=(ll)y;now--; q.push(Node(x-y,i)); } if(now<0) { if(q.empty()) { hh=1; continue; } Node p=q.top();q.pop(); a[p.pos]='('; now+=2;ans+=(ll)p.val; } } if(now!=0) hh=1; if(!hh) printf("%lld\n%s",ans,a); else printf("-1"); return 0; }