题目大意
给出两个串,每次操作可以将当前串的一个字符移到它前面的任意位置,求到目标串的最小操作数及其步骤。
解题思路
对两个串做变种的lcs,f[i][j]表示原串匹配到i,当前串匹配到j的lcs,转移保证i不小于j且前i个字符包含前j个字符。用另外的数组保留转移方式,构造解的时候贪心构造即可。
code
using namespace std;
int const mn=2000+9,inf=1e9+7;
int t,n,cnt1[30],cnt2[30],match[mn],tag[mn],f[mn][mn],pi[mn][mn],pj[mn][mn];
char s1[mn],s2[mn];
int main(){
//freopen("chinese.in","r",stdin);
//freopen("chinese.out","w",stdout);
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d\n",&t);
fo(cas,1,t){
scanf("%s\n%s\n",s1+1,s2+1);int n=strlen(s1+1);
fo(i,1,n)fo(j,1,n)f[i][j]=0;
fo(i,0,25)cnt1[i]=cnt2[i]=0;
int k=1;cnt1[s1[1]-'a']=1;
fo(j,1,n){
int ch=s2[j]-'a';cnt2[ch]++;
for(;cnt1[ch]<cnt2[ch];k++){
cnt1[s1[k+1]-'a']++;
if(f[k-1][j]>f[k][j]){
f[k][j]=f[k-1][j];
pi[k][j]=k-1;pj[k][j]=j;
}
}
fo(i,k,n){
int tmp=max(f[i-1][j],f[i][j-1]),tmpp=max(tmp,f[i-1][j-1]+(s1[i]==s2[j]));
f[i][j]=tmpp;
if(tmpp==f[i-1][j])pi[i][j]=i-1,pj[i][j]=j;
else if(tmpp==f[i][j-1])pi[i][j]=i,pj[i][j]=j-1;
else pi[i][j]=i-1,pj[i][j]=j-1;
}
}
int i=n,j=n;
fo(i,1,n)match[i]=tag[i]=0;
while(i&&j){
while((pi[i][j]==i)||(pj[i][j]==j)){
int ni=pi[i][j],nj=pj[i][j];
i=ni;j=nj;
}
match[i]=j;tag[j]=1;
int ni=pi[i][j],nj=pj[i][j];
i=ni;j=nj;
}
printf("%d\n",n-f[n][n]);
fo(i,1,n)if(!match[i]){
int tmp;
fo(j,i+1,n)if((!tag[j])&&(s1[i]==s2[j])){tmp=j;break;}
printf("%d %d\n",tmp,i);
fo(j,i+1,n)if(match[j]&&(match[j]<=tmp)){
tag[match[j]]--;
tag[++match[j]]++;
}
int tmpp=s2[tmp];
fd(j,tmp,i+1)s2[j]=s2[j-1];
s2[i]=tmpp;
}
}
return 0;
}