感觉这题真好!
/* 首先可以将操作换一种理解方式:取s[i]然后插到其左边任一位置 可以发现从s->t是一个凑后缀的过程 那么我们将s,t翻转,将操作变成取s[i]然后插到右边任一位置,于是s->t变成了凑前缀的过程 dp[i][j]表示s[1..i]凑出t[1..j]的代价 如果s[1..i]能凑出t[1..j],那么进入转移: dp[i][j]=dp[i-1][j]+1(s[1..i-1]已经和t[1..j]匹配,s[i]向后挪动) dp[i][j]=dp[i][j-1] (s[1..i]已经和t[1..j-1]匹配,再找一个前面往后挪的和t[j]匹配) s[i]==t[j]:dp[i][j]=dp[i-1][j-1](s[i]不用向后挪动,直接和t[j]匹配) dp[i][0]=i */ #include<bits/stdc++.h> using namespace std; #define N 2005 char s[N],t[N]; int n,dp[N][N],p1[N][26],p2[N][26]; void reverse(char s[]){ int i=1,j=n; while(i<j)swap(s[i],s[j]),++i,--j; } int main(){ int T;cin>>T; while(T--){ scanf("%d%s%s",&n,s+1,t+1); reverse(s); reverse(t); for(int i=0;i<=n;i++) for(int j=0;j<=n;j++)dp[i][j]=1e7; for(int i=0;i<=n;i++)dp[i][0]=i; for(int i=1;i<=n;i++){ for(int j=0;j<26;j++){ if(s[i]-'a'==j)p1[i][j]=p1[i-1][j]+1; else p1[i][j]=p1[i-1][j]; if(t[i]-'a'==j)p2[i][j]=p2[i-1][j]+1; else p2[i][j]=p2[i-1][j]; } } int f=0; for(int i=0;i<26;i++) if(p1[n][i]!=p2[n][i]) f=1; if(f){puts("-1");continue;} for(int i=1;i<=n;i++) for(int j=1;j<=i;j++){ //判是否可行 int f=0; for(int k=0;k<26;k++) if(p1[i][k]<p2[j][k])f=1; if(f)continue; if(dp[i-1][j]<1e7) dp[i][j]=min(dp[i][j],dp[i-1][j]+1); if(dp[i][j-1]<1e7) dp[i][j]=min(dp[i][j],dp[i][j-1]); if(s[i]==t[j] && dp[i-1][j-1]<1e7) dp[i][j]=min(dp[i][j],dp[i-1][j-1]); } if(dp[n][n]<1e7)cout<<dp[n][n]<<' '; else cout<<-1<<' '; } }