【CF3D Least Cost Bracket Sequence】题解
题目链接
题目
This is yet another problem on regular bracket sequences.
A bracket sequence is called regular, if by inserting "+" and "1" into it we get a correct mathematical expression. For example, sequences "(())()", "()" and "(()(()))" are regular, while ")(", "(()" and "(()))(" are not. You have a pattern of a bracket sequence that consists of characters "(", ")" and "?". You have to replace each character "?" with a bracket so, that you get a regular bracket sequence.
For each character "?" the cost of its replacement with "(" and ")" is given. Among all the possible variants your should choose the cheapest.
给一个序列,序列里面会有左括号、问号、右括号。对于一个‘?’而言,可以将其替换为一个‘(’,也可以替换成一个‘)’,但是都有相应的代价。问:如何替换使得代价最小。前提是替换之后的序列中,括号是匹配的。如果不能替换为一个括号匹配的序列则输出-1。
思路
先把序列中所有的问号变成右半括号,当不够左半括号时,把前面代价最小的一个右半括号变成左半括号即可,这个过程可以用优先队列来维护。
总结
这是一道非常好的思维题。
一开始我想的是 \(O(n^2)\) 的dp(就是枚举前 \(i\) 个字符中有 \(j\) 个左半括号待匹配的最小代价),这会超时。
我看了一下标签,优先队列,自然想到可撤销贪心,但推出的方法具有后效性。
后来看题解,才发现可以把所有问号先变成右半括号。其实原因是在枚举过程中,右半括号必须满足前面有对应的左半括号,而左半括号无限制,只需要最后满足即可。于是可以先把题目中的变量变成具有限制的量,而可撤销贪心是可以撤销成无限制的量,以消除后效性。
同时,对于这种每种物品只有两个转态的,可以多想想可撤销贪心。
Code
// Problem: CF3D Least Cost Bracket Sequence
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF3D
// Memory Limit: 62 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 50010
struct node
{
int x, a, b;
bool operator <(const node &A) const
{
//-b+a -A.b+A.a
return a-b>A.a-A.b;
}
}t;
int n, m, i, j, k, ans;
char s[N];
int a[N], b[N];
priority_queue<node>q;
signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
scanf("%s", s+1);
n=strlen(s+1);
if(n&1) return printf("-1"), 0;
for(i=1; i<=n; ++i) m+=(s[i]=='?');
for(i=1; i<=m; ++i) a[i]=read(), b[i]=read();
for(i=1; i<=n; ++i)
{
if(s[i]=='(') {++k; continue; }
if(s[i]=='?')
{
s[i]=')';
t.x=i; t.a=a[++j]; t.b=b[j];
ans+=b[j];
q.push(t);
}
if(s[i]==')')
{
if(!k)
{
if(q.empty()) return printf("-1"), 0;
t=q.top(); q.pop();
// printf("%lld ", t.x);
ans-=t.b; ans+=t.a;
s[t.x]='(';
k=2;
}
--k;
}
}
if(k) return printf("-1"), 0;
printf("%lld\n%s", ans, s+1);
return 0;
}
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/15728520.html