是不是和最长公共子序列很像?对,就是那样dp,不过需要预处理每个颜色开始的位置和结束的位置,才能知道放入这个颜色后,会使结果增加多少。这题开始我一直TLE。。原因是我用memset()初始化5000*5000的数组,才知道那个函数在数据大的时候耗时是多么可怕!
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#define INF 10000
#define ll long long
#define max3(a,b,c) max(a,max(b,c))
#define MAXN 100010
using namespace std;
char str1[5010];
char str2[5010];
int first[26][2];
int last[26][2];
int dp[5010][5010];
int tab[5010][5010];
int main(){
int t;
cin>>t;
while(t--){
scanf("%s%s",str1+1,str2+1);
int len1=strlen(str1+1);
int len2=strlen(str2+1);
memset(first,-1,sizeof(first));
memset(last,-1,sizeof(last));
for(int i=1;i<=len1;i++){
if(first[str1[i]-65][1]==-1 )
first[str1[i]-65][1]=i;
}
for(int i=1;i<=len2;i++){
if(first[str2[i]-65][0]==-1 )
first[str2[i]-65][0]=i;
}
//
for(int i=len1;i>=1;i--){
if(last[str1[i]-65][1]==-1 )
last[str1[i]-65][1]=i;
}
for(int i=len2;i>=1;i--){
if(last[str2[i]-65][0]==-1 )
last[str2[i]-65][0]=i;
}
//
for(int i=0;i<=len1;i++){
for(int j=0;j<=len2;j++){
int re=0;
for(int k=0;k<26;k++){
if( ( (i>=first[k][1]&&first[k][1]!=-1) || (j>=first[k][0]&&first[k][0]!=-1 )) &&
( (i<last[k][1] &&last[k][1]!=-1)|| (j<last[k][0]&&last[k][0]!=-1) ) ){
re++;
}
}
tab[i][j]=re;
}
}
dp[0][0]=0;
for(int i=1;i<=len1;i++){
dp[i][0]=dp[i-1][0]+tab[i][0];
}
for(int i=1;i<=len2;i++){
dp[0][i]=dp[0][i-1]+tab[0][i];
}
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
dp[i][j]=min( dp[i-1][j] , dp[i][j-1] )+tab[i][j];
}
}
cout<<dp[len1][len2]<<endl;
}
return 0;
}