AT_agc026_e [AGC026E] Synchronized Subsequence 题解
考虑 dp,记 \(f_i\) 表示第 \(i\sim n\) 个 a 和 b 得到的字典序最大的字符串。记 \(a_i,b_i\) 表示第 \(i\) 个 a 或 b 的位置。不取直接从 \(f_{i+1}\) 转移即可,接下来考虑取的情况:
- 若 \(a_i<b_i\),则 \((a_i,b_i)\) 中只存在 \(<i\) 的
b和 \(>i\) 的a,显然后者删除更优。考虑找到最小的 \(j\) 满足 \(a_j>b_i\),在前面添上ab转移。 - 若 \(a_i>b_i\),则 \((b_i,a_i)\) 中只存在 \(<i\) 的
a和 \(>i\) 的b,显然后者保留更优。考虑不断往后扫把当前区间能覆盖到的ba对全都取了,直到 \((b_j,a_j)\) 中不存在b,再拼上 \(f_{j+1}\) 转移。
时间复杂度 \(\mathcal O(n^2)\)。
参考代码:
#include<bits/stdc++.h>
#define mxn 3003
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n,t1,t2,d[mxn<<1],a[mxn],b[mxn];
char s[mxn<<1];
string f[mxn];
signed main(){
scanf("%d%s",&n,s+1);
rep(i,1,n<<1){
if(s[i]=='a')a[d[i]=++t1]=i;
else b[d[i]=++t2]=i;
}
drep(i,n,1){
if(a[i]<b[i]){
int j=i+1;
for(;j<=n&&a[j]<b[i];++j);
f[i]=max(f[i+1],"ab"+f[j]);
}else{
int j=b[i];
for(;j<=n<<1&&a[d[j]]>b[d[j]]&&(d[j]<=i||b[d[j]]<a[d[j]-1]);++j){
if(d[j]>=i)f[i]+=s[j];
}
f[i]=max(f[i]+f[d[j]],f[i+1]);
}
}
cout<<f[1];
return 0;
}

浙公网安备 33010602011771号