2025-02-21 19:08阅读: 6评论: 0推荐: 0

UVA1625 颜色的长度/小车的颜色 题解

Tag:动态规划

题目描述

link

输入两个长度分别是 nm(n,m5000) 的颜色序列,要求按顺序合并成同一个序列,即每次可以把一个序列开头的颜色放到新序列的尾部。

例如,两个颜色序列 GBBYYRRGB,至少有两种合并结果:GBYBRYRGBYRRGGBBYB。对于每种颜色来说其跨度 L(c) 等于最大位置和最小位置之差。例如,对于上面两种合并结果,每种颜色的 L(c) 和所有 L(c) 的总和如下表所示:

Color G Y B R -> Sum
GBYBRYRGB 7 3 7 2 -> 19
YRRGGBBYB 1 7 3 1 -> 12

你的任务是找一种合并方式,使得所有 L(c) 的总和最小。

思路

我们定义 dpi,j 表示序列 Ai 个颜色和序列 Bj 个颜色合在一起的最小贡献。

那转移就可以分两种情况讨论:

1.把 Ai 移到前 i+j1 个颜色的后面。(即从 dpi1,j 转移过来)

因为 A1Ai1,B1Bj 一定在 Ai 前面,Ai+1An,Bj+1Bm 一定在 Ai 后面,计算贡献时只需要预处理四个前后缀数组判断前后是否同色就行了。

  • 前面有同色且后面没有 +(i+j)

  • 前面没有同色且后面有 (i+j)

  • 前后都无同色或都有 +0

2.把 Aj 移到前 i+j1 个颜色的后面。(即从 dpi,j1 转移过来)

同理可得。

具体细节见代码。

#include<bits/stdc++.h>
#define PII pair<int,int>
#define ll long long
using namespace std;
const int N=5005;
int t,n,m;
string a,b;
bool qa[N][26],ha[N][26];
bool qb[N][26],hb[N][26];
int dp[N][N];
int main() {
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	while(t--) {
		cin>>a>>b;
		n=a.size();
		m=b.size();
		a=" "+a;
		b=" "+b;
		memset(qa,0,sizeof(qa));
		memset(ha,0,sizeof(ha));
		memset(qb,0,sizeof(qb));
		memset(hb,0,sizeof(hb));
		for(int i=1; i<=n; i++) {
			for(int j=0; j<='Z'-'A'; j++) {
				qa[i][j]=qa[i-1][j]||(a[i]==char(j+'A'));
			}
		}
		for(int i=1; i<=m; i++) {
			for(int j=0; j<='Z'-'A'; j++) {
				qb[i][j]=qb[i-1][j]||(b[i]==char(j+'A'));
			}
		}
		for(int i=n; i>=0; i--) {//注意后缀要赋值到0 
			for(int j=0; j<='Z'-'A'; j++) {
				ha[i][j]=ha[i+1][j]||(a[i]==char(j+'A'));
			}
		}
		for(int i=m; i>=0; i--) {//注意后缀要赋值到0 
			for(int j=0; j<='Z'-'A'; j++) {
				hb[i][j]=hb[i+1][j]||(b[i]==char(j+'A'));
			}
		}
		memset(dp,0x3f,sizeof dp);
		dp[0][0]=0;
		for(int i=0; i<=n; i++) {//从0开始 
			for(int j=0; j<=m; j++) {//从0开始 
				if(i!=0) {
					bool q=qa[i-1][a[i]-'A']||qb[j][a[i]-'A'];
					bool h=ha[i+1][a[i]-'A']||hb[j+1][a[i]-'A'];
					if(!q&&h) dp[i][j]=min(dp[i][j],dp[i-1][j]-i-j);
					else if(q&&!h) dp[i][j]=min(dp[i][j],dp[i-1][j]+i+j);
					else dp[i][j]=min(dp[i][j],dp[i-1][j]);
				}
				if(j!=0)
				{
					bool q=qa[i][b[j]-'A']||qb[j-1][b[j]-'A'];
					bool h=ha[i+1][b[j]-'A']||hb[j+1][b[j]-'A'];
					if(!q&&h) dp[i][j]=min(dp[i][j],dp[i][j-1]-i-j);
					else if(q&&!h) dp[i][j]=min(dp[i][j],dp[i][j-1]+i+j);
					else dp[i][j]=min(dp[i][j],dp[i][j-1]);
				}
			}
		}
		cout<<dp[n][m]<<"\n";
	}
	return 0;
}

本文作者:yaaaaaan

本文链接:https://www.cnblogs.com/yaaaaaan/p/18729879

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   yaaaaaan  阅读(6)  评论(0编辑  收藏  举报
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
点击右上角即可分享
微信分享提示