你有两个序列,每个序列都由颜色的缩写组成(如RRRGGGBBBBBBB),现在通过每次挑一个序列,把序列中首位的颜色提出来放到新序列的尾部,把两个序列合成一个序列。设L(c)是颜色c最右位置和最左位置的差,求所有L和的最小值。
当一个颜色c被放入新序列而没有结束(原序列中还有该颜色)时,每次放入一个颜色Lc就要加一。所以只要知道有多少个颜色还没有结束,然后加就行了。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn=5010, INF=0x3f3f3f3f;
int n,m;
char a[maxn],b[maxn];
int d[maxn][maxn],bg[30][2],ed[30][2],w[maxn][maxn];
void dp()
{
memset(bg,0,sizeof(bg));
memset(ed,0,sizeof(ed));
for(int i=0;i<26;i++)
bg[i][0]=bg[i][1]=INF;
for(int i=1;i<=n;i++)
{
int c=a[i]-'A';
if(bg[c][0]==INF)
bg[c][0]=i;
ed[c][0]=i;
}
for(int i=1;i<=m;i++)
{
int c=b[i]-'A';
if(bg[c][1]==INF)
bg[c][1]=i;
ed[c][1]=i;
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
{
if(i==0&&j==0)
continue;
int t1=INF,t2=INF;
if(i>0)
t1=d[i-1][j]+w[i-1][j];
if(j>0)
t2=d[i][j-1]+w[i][j-1];
d[i][j]=min(t1,t2);
if(i>0)
{
w[i][j]=w[i-1][j];
int c=a[i]-'A';
if(bg[c][0]==i&&bg[c][1]>j) w[i][j]++;
if(ed[c][0]==i&&ed[c][1]<=j) w[i][j]--;
}
else
{
w[i][j]=w[i][j-1];
int c=b[j]-'A';
if(bg[c][1]==j&&bg[c][0]>i) w[i][j]++;
if(ed[c][1]==j&&ed[c][0]<=i) w[i][j]--;
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%s%s",a+1,b+1);
n=strlen(a+1),m=strlen(b+1);
dp();
cout<<d[n][m]<<endl;
}
return 0;
}