对于一个颜色 开始时把他存储到计数器数组c中
结束时再减去 这样可以直接无视中间的变化过程
c[i][j]表示在str1 的i 位置 str2 的j位置 已经开始遍历但未遍历结束的颜色的数量 是一个递推的过程
可以先预处理
dp很简单 难的时上面的c数组
dp意思时 前一个状态的最优加上未结束的颜色数量
总共俩状态 取最小就是最优
#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a));
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=5010;
int dp[maxn][maxn];
int c[maxn][maxn];
char p[maxn],q[maxn];
int sp[27],ep[27],sq[27],eq[27];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
for (int i = 0; i < 26; i++)
{
sp[i]=sq[i]=INF;
ep[i]=eq[i]=0;
}
scanf("%s",p+1);
scanf("%s",q+1);
int n=strlen(p+1);
int m=strlen(q+1);
for(int i=1;i<=n;i++) p[i]-='A';
for(int i=1;i<=m;i++) q[i]-='A';
for(int i=1;i<=n;i++)
{
sp[p[i]]=min(sp[p[i]],i);
ep[p[i]]=i;
}
for(int i=1;i<=m;i++)
{
sq[q[i]]=min(sq[q[i]],i);
eq[q[i]]=i;
}
//for (int i = 0; i < 26; i++)
//{
// cout<<sp[i]<<" "<<sq[i]<<" "<<ep[i]<<" "<<eq[i]<<endl;
//}
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(i)
{
c[i][j]=c[i-1][j];
if(sp[p[i]]==i&&j<sq[p[i]]) c[i][j]++;//j<sq[q[i]]另一个字符串的q[i]没走完 //当p中只有一个颜色时 q还有 那么它就是起点
if(ep[p[i]]==i&&j>=eq[p[i]]) c[i][j]--;
}
else if(j)//只在i==0时进入
{
c[i][j]=c[i][j-1];
if(sq[q[j]]==j&&i<sp[q[j]]) c[i][j]++;
if(eq[q[j]]==j&&i>=ep[q[j]]) c[i][j]--;
}
}
}
/*for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
cout<<c[i][j]<<" ";
}
cout<<endl;
}*/
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(!i&&!j) continue;
int v1=INF,v2=INF;
if(i) v1=dp[i-1][j]+c[i-1][j];
if(j) v2=dp[i][j-1]+c[i][j-1];
dp[i][j]=min(v1,v2);
}
}
printf("%d\n",dp[n][m]);
}
}