AT_agc026_e [AGC026E] Synchronized Subsequence 题解

考虑 dp,记 \(f_i\) 表示第 \(i\sim n\)ab 得到的字典序最大的字符串。记 \(a_i,b_i\) 表示第 \(i\)ab 的位置。不取直接从 \(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;
}
posted @ 2025-05-13 23:47  zifanwang  阅读(10)  评论(0)    收藏  举报