*题解: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;
}

浙公网安备 33010602011771号