dp[i][j]表示前一个序列拿了i个颜色,后一个序列拿了j个颜色的最小花费。
转移的时候显然只能向dp[i+1][j],或dp[i][j+1]转移,每增加拿走一个颜色,之前已经出现但没结束的颜色个数的跨度都增加1,为了在转移的时候快速算出这个值,先预处理出每个颜色在各个序列中的起始和终止位置。
memset (dp),然后就GG了
#include<bits/stdc++.h> using namespace std; #define FOR(i,s,e) for(int i = s; i < e; i++) #define RFOR(i,e,s) for(int i = e-1; i >= s; i--) #define bug(x) cout<<#x<<'='<<endl #define MP make_pair #define PB push_back #define fi first #define se second #define CLR(x) memset(x,0,sizeof(x)); #define CLRTo(x,v) memset(x,v,sizeof(x)); const int maxn = 5001; int dp[maxn][maxn]; const int N = 26; char s1[maxn]; char s2[maxn]; bool vis[N]; int ed2[N],ed1[N]; int st1[N],st2[N]; #define GetEd(x) CLR(vis); for(i = n##x-1; i >= 0; i--){ int id = s##x[i] - 'A'; if(!vis[id]){ vis[id] = true; ed##x[id] = i; } } #define GetSt(x) CLR(vis); for(i = 0; s##x[i]; i++){ int id = s##x[i] - 'A'; if(!vis[id]){ vis[id] = true; st##x[id] = i; } } n##x = i; int cal(int i,int j) { int ret = 0; for(int k = 0; k < N; k++){ bool f1 = j>=st2[k] || i>=st1[k]; bool f2 = j<ed2[k] || i < ed1[k]; ret += f1&&f2; } return ret; } const int INF = 0x3fffffff; int main() { //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while(T--){ scanf("%s%s",s1,s2); int i; int n1 ,n2 ; fill(st1,st1+N,INF); fill(st2,st2+N,INF); fill(ed1,ed1+N,-INF); fill(ed2,ed2+N,-INF); GetSt(1) GetSt(2) GetEd(1) GetEd(2) for(i = 0; i <= n1; i++){ for(int j = 0; j <= n2; j++){ if(i&&j){ dp[i][j] = min(dp[i-1][j],dp[i][j-1])+cal(i-1,j-1); }else { if(i){ dp[i][j] = dp[i-1][j]+cal(i-1,j-1); }else if(j){ dp[i][j] = dp[i][j-1]+cal(i-1,j-1); }else { dp[i][j] = 0; } } } } printf("%d ",dp[n1][n2]); } return 0; }