题目:
有$a$,$b$两串字符串,现用$a$,$b$构成一个新的一个字符串,规则如下:每次只能取$a$或$b$中一个头放在新的子串的末尾。定义跨度费用:同一个字母相隔的最长距离。问新构成的字符串跨度费用最小是多少。
分析:
$dp$。$dp[i][j]=a$移出$i$个,$b$移出$j$个还需花费的最小费用。$c[i][j]=i$,$j$移出后有多少没结束的组。
code:
#define debug
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7;
const int MAXN = 5e3 + 10;
const ll INF = 0x3f3f3f3f;
const ll inf = 0x7fffff;
const ll mod = 1e9 + 7;
const int MOD = 10007;
int dp[MAXN][MAXN],c[MAXN][MAXN];
int sa[26],sb[26],ea[26],eb[26];
string a,b;
int f(char a) {
return a-'A';
}
void initStr(int (&s)[26],int (&e)[26],string str,int len) {
for(int i=1; i<=len; i++) {
s[f(str[i])]=min(s[f(str[i])],i);
e[f(str[i])]=i;
}
}
void solve() {
int t;
cin>>t;
while(t--) {
cin>>a>>b;
a=" "+a;
b=" "+b;
int la=a.size(),lb=b.size();
for(int i=0; i<26; i++) {
sa[i]=sb[i]=INF;
ea[i]=eb[i]=-INF;
}
initStr(sa,ea,a,la);
initStr(sb,eb,b,lb);
dp[0][0]=c[0][0]=0;
for(int i=0; i<=la; i++) {
for(int j=0; j<=lb; 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);
if(i) {
int aa=f(a[i]);
c[i][j]=c[i-1][j];
if(sa[aa]==i&&sb[aa]>j)c[i][j]++;
if(ea[aa]==i&&eb[aa]<=j)c[i][j]--;
} else if(j) {
int bb=f(b[j]);
c[i][j]=c[i][j-1];
if(sb[bb]==j&&sa[bb]>i)c[i][j]++;
if(eb[bb]==j&&ea[bb]<=i)c[i][j]--;
}
}
}
cout<<dp[la][lb]<<endl;
}
}
int main(int argc, char const *argv[]) {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#ifdef debug
freopen("in.txt", "r", stdin);
freopen("out.txt","w",stdout);
#endif
int T=1;
// cin>>T;
while(T--)
solve();
return 0;
}