【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; 
}

posted @ 2021-12-24 18:32  zhangtingxi  阅读(57)  评论(0编辑  收藏  举报