题解:CF1701E Text Editor
maxiaomeng · · 题解
CF1701E Text Editor
最优解有两种情况:
- 只从后往前移动或删除字符。
- 从后往前移动或删除字符,然后按下 Home 键,在从前往后移动和删除字符。
对于第一种情况,直接求大力求 LCP 长度
对于第二种情况,贪心地想,在后面删几下,按 Home 键,再在前面删几下,再按 End 键,再在在后面删几下的方案一定不如在后面删完后再按 Home 键把前面删完。
因此我们可以将
先假设一开始每个字符有
所以定义状态
- 当
s_i=t_j 时,f_{i,j,k}=f_{i-1,j-1,k-1} 。 - 当
k = 0 时,f_{i,j,k}=\max\limits_{l=0}^{j}[\max(f_{i-1,j,l},l+j-i)] 。
但该转移方程需要最后一次操作是删除才能更新 #)强迫其删除并更新。
该转移方程空间复杂度和时间复杂度均为
式子
式子
经过以上优化,代码时间复杂度和空间复杂度均为
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N=5005;
int t,n,m,mx[N];
pair<int,int>tmx[N];
char a[N],b[N];
list<int>f[N];
inline void solve(){
cin>>n>>m>>a+1>>b+1;
a[n+1]='#';
a[n+2]=0;
++n;
for(int i=0;i<=m;i++)f[i].clear(),tmx[i]={0x80808080,0x80808080},mx[i]=0x80808080;
f[0].push_back(0);
mx[0]=0;
tmx[0]={0,0x80808080};
for(int i=1;i<=n;i++){
for(int j=m;j>=1;j--){
if(a[i]==b[j]){
f[j].swap(f[j-1]);
swap(mx[j],mx[j-1]);
}
}
for(int j=m;j>=1;j--){
if(a[i]!=b[j]){
f[j].clear(),mx[j]=0x80808080;
}
}
for(int j=m;j>=1;j--){
if(a[i]==b[j]&&!f[j].empty()){
f[j].push_back(0x80808080);
if(f[j].size()>j+1)f[j].pop_front();
}
}
for(int j=0;j<=m;j++){
if(max(tmx[j].first,tmx[j].second)==0x80808080)continue;
if(f[j].empty())f[j].push_back(0x80808080);
f[j].back()=max(f[j].back(),max(tmx[j].first,tmx[j].second));
mx[j]=max(mx[j],f[j].back());
}
for(int j=0;j<=m;j++){
if(!f[j].empty())tmx[j]={mx[j],int(f[j].size())-1+j-i};
else tmx[j]={0x80808080,0x80808080};
}
// for(int j=0;j<=m;j++){
// cout<<mx[j]<<','<<f[j].size()<<' ';
// }
// cout<<'\n';
}
if(f[m].empty())cout<<"-1\n";
else{
--n;
int r=1+n-f[m].front();
int z=0,s=0;
for(int i=1;i<=n;i++){
if(i>m||a[i]!=b[i]){
break;
}else{
++z;
}
}
s=n-z;
cout<<min(r,s)<<'\n';
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)solve();
return 0;
}