分析一下发现如果每一次放进去一个新,它就会对所有覆盖这个点的所有颜色的L加1那么另add(i,j)为第一个放到i第二个放到j放完之后这种状态有多少组交叉那么有
int add(int x, int y) {
int cnt = 0;
for(int i=0;i<26;i++){
if(pos[i][1] <= x && pos2[i][1] <= y) continue;
if(pos[i][0] > x && pos2[i][0] > y) continue;
if(pos[i][0] > x && pos2[i][0] == -1) continue;
if(pos2[i][0] > y && pos[i][0] == -1) continue;
cnt++;
}
return cnt;
}
之前可以先预处理一下每一种颜色在每一段中的起始位置和结束位置
void Init(){
memset(pos, -1, sizeof pos);
memset(pos2, -1, sizeof pos2);
int len = strlen(s1+1);
for(int i=1;i<=len;i++)
pos[s1[i]-'A'][1] = i;
for(int i=len;i>=1;i--)
pos[s1[i]-'A'][0] = i;
len = strlen(s2+1);
for(int i=1;i<=len;i++)
pos2[s2[i]-'A'][1] = i;
for(int i=len;i>=1;i--)
pos2[s2[i]-'A'][0] = i;
}
然后很容易发现f(i,j)=min{f(i−1,j),f(i,j−1)}+add(i,j)记得要用滚动数组,不然直接二位数组要爆
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100000;
int pos[26][2], pos2[26][2];
char s1[MAXN+10], s2[MAXN+10];
void Init(){
memset(pos, -1, sizeof pos);
memset(pos2, -1, sizeof pos2);
int len = strlen(s1+1);
for(int i=1;i<=len;i++)
pos[s1[i]-'A'][1] = i;
for(int i=len;i>=1;i--)
pos[s1[i]-'A'][0] = i;
len = strlen(s2+1);
for(int i=1;i<=len;i++)
pos2[s2[i]-'A'][1] = i;
for(int i=len;i>=1;i--)
pos2[s2[i]-'A'][0] = i;
}
int add(int x, int y) {
int cnt = 0;
for(int i=0;i<26;i++){
if(pos[i][1] <= x && pos2[i][1] <= y) continue;
if(pos[i][0] > x && pos2[i][0] > y) continue;
if(pos[i][0] > x && pos2[i][0] == -1) continue;
if(pos2[i][0] > y && pos[i][0] == -1) continue;
cnt++;
}
return cnt;
}
const int INF = 999999999;
int dp[2][MAXN+5];
int solve(){
memset(dp, 0, sizeof dp);
int now = 0, len1 = strlen(s1+1), len2 = strlen(s2+1);
for(int i=1;i<=len2;i++) dp[now][i] = INF;
for(int i=0;i<=len1;i++){
now ^= 1;
for(int j=0;j<=len2;j++)
dp[now][j] = min(((j-1)>=0?dp[now][j-1]:INF), dp[now^1][j]) + add(i, j);
}
return dp[now][len2];
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%s%s", s1+1, s2+1);
Init();
printf("%d\n", solve());
}
}