*题解:CF2233C Cost of a Bracket Sequence

题目链接

解析

首先考虑怎么求最长合法括号子序列。可以直接开一个栈,每次遇到 “\(\texttt{(}\)” 就将其压入栈中,每次遇到 “\(\texttt{)}\)” 就尝试将其与栈顶的 “\(\texttt{(}\)” 匹配,匹配成功即可对答案做贡献。

回到本题,本题要求删去一些括号后使得最长合法括号子序列长度最短。想想怎么删是最优的。可以发现,删左括号时,删除更靠左边的左括号必定不劣,因为左括号越左,其能影响到的右括号个数越多。删右括号时同理。

于是就有了这样一个策略,删一段前缀中的所有左括号和一段后缀中的所有右括号。枚举删掉的左括号数量,然后统计此时最长合法括号子序列,取最优的方案即可。

时间复杂度 \(O(n ^ 2)\)

代码

/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 5e3 + 5,M = 5e5 + 5,P = 2000000,mod = 998244353;
bool res[N],f[N];
string s;
int n,k;
int chk(){//求的是括号对数
	stack<int> st;
	int cnt = 0;
	for(int i=1;i<=n;i++)if(f[i]){
		if(s[i] == '('){
			st.push(i);
		}else{
			if(!st.empty()){
				st.pop();
				cnt++;
			}
		}
	}
	return cnt;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;
	cin>>T;
	while(T--){	
		cin>>n>>k;
		cin>>s;
		s = "!" + s;	
		int mn = n;
		for(int i=0;i<=k;i++){
			int l = i,r = k - i;
			for(int j=1;j<=n;j++){
				f[j] = true;
			}
			for(int j=1;j<=n && l;j++){
				if(s[j] == '('){
					l--;
					f[j] = false;
				}
			}
			for(int j=n;j>=1 && r;j--){
				if(s[j] == ')'){
					r--;
					f[j] = false;
				}
			}
			int x = chk();
			if(x < mn){
				mn = x;
				for(int j=1;j<=n;j++){
					res[j] = f[j] ^ 1;
				}
			}
		}
		for(int i=1;i<=n;i++){
			cout<<res[i];
			res[i] = 0;
		}
		cout<<'\n';
	}
	return 0;
}
posted @ 2026-06-10 17:36  yutar  阅读(38)  评论(0)    收藏  举报