题目:
有$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; }