UVA

题目:

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

  

原文地址:https://www.cnblogs.com/visualVK/p/10346625.html