题解:P17296 [ICPC 2026 Xi'an I] Palindromic and Balanced
lailai0916 · · 题解
题意简述
求给定括号串的最长子序列。该子序列需要是合法括号序列,且删去首尾字符后为回文串。
解题思路
非空答案的首字符只能是 (,末字符只能是 )。把这两个字符删去,记剩余回文串为
完整答案是合法括号序列,所以在进入末尾右括号前,所有前缀都不能低于
由于
于是每个 () 或 )(。
回文会把最左一组倒序映到最右一组。因此,首尾两组的类型必定相反。递归删除首尾两组后,内部仍满足相同条件。合法的
- 空串;
- 在同类字符串两侧分别添加
()与)(; - 在同类字符串两侧分别添加
)(与()。
设
若
预处理每个位置前后最近的两种括号。设
取最靠左的
这些转移只会产生递归规则允许的字符串。反过来,任取一个最优子序列。若它缺少某个区间端点,舍弃端点的转移会保留它。若它同时使用两端,其首尾两组必然由两个同字符端点与两个相反字符组成;最近位置留下的内部区间更大,归纳可知对应转移不会更差。
按区间长度递增计算 ( 且右侧存在 ),便用 () 单独统计。
每组数据的时间复杂度为
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=5005;
int f[N][N],pre[N][2],nxt[N][2];
void solve()
{
int n;
string s;
cin>>n>>s;
s=' '+s;
pre[0][0]=pre[0][1]=0;
for(int i=1;i<=n;i++)
{
pre[i][0]=pre[i-1][0];
pre[i][1]=pre[i-1][1];
pre[i][s[i]==')']=i;
}
nxt[n+1][0]=nxt[n+1][1]=n+1;
for(int i=n;i>=1;i--)
{
nxt[i][0]=nxt[i+1][0];
nxt[i][1]=nxt[i+1][1];
nxt[i][s[i]==')']=i;
}
int ans=0;
for(int i=1;i<=n;i++)if(s[i]==')'&&pre[i-1][0])ans=2;
for(int k=1;k<=n;k++)
{
for(int i=1,j=k;j<=n;i++,j++)
{
f[i][j]=max(f[i+1][j],f[i][j-1]);
if(s[i]==s[j])
{
int c=s[i]=='(';
int x=nxt[i+1][c],y=pre[j-1][c];
if(x<y)f[i][j]=max(f[i][j],f[x+1][y-1]+4);
}
if(pre[i-1][0]&&nxt[j+1][1]<=n)ans=max(ans,f[i][j]+2);
}
}
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin>>t;
while(t--)solve();
return 0;
}