链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4500

题意:

输入两个长度分别为n和m(n,m≤5000)的颜色序列,要求按顺序合并成同一个序列,即每次可以把一个序列开头的颜色放到新序列的尾部。
对于每个颜色c来说,其跨度L(c)等于最大位置和最小位置之差。你的任务是找一种合并方式,使得所有L(c)的总和最小。

分析:

首先,因为选取顺序的问题,该题满足无后效性。
也满足最优子结构性质:当在部分最终序列的后面添加一个颜色时,需要把所有“已经出现但还没结束”的颜色的L(c)值加1。
这样,部分最终序列的L(c)值之和越小越好,即只需保留其最小值。
设d(i,j)表示两个序列已经分别移走了i和j个元素的最小费用。
当把一个颜色移到最终序列前,需要把所有“已经出现但还没结束”的颜色的L(c)值加1。
因为并不关心每个颜色的L(c),所以只需要知道有多少种颜色已经开始但尚未结束。
这样,可以事先算出每个颜色在两个序列中的开始和结束位置,
就可以在动态规划时在O(1)时间内计算出状态d(i,j)中“有多少个颜色已经出现但尚未结束”(用c数组记录)。
因为序列a[1..i]与序列b[1...j]组成的序列的最后一个字符必然是a[i]或b[j],
所以状态转移方程为:dp(i,j) = min(dp(i-1,j) + c[i-1][j] , dp(i,j-1) + c[i][j-1])。

代码:

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int INF = 0x3f3f3f3f;
const int UP = + ;
int sa[], sb[], ea[], eb[]; // sa[i]代表序列a中颜色i的开始位置
int d[][UP], c[][UP]; // d[i][j]为两个序列分别移走了i和j个元素的最小费用,c数组记录有多少个颜色已经出现但尚未结束,d, c均为滚动数组
char a[UP], b[UP]; // 元素序号从1开始 int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%s%s", a+, b+);
int La = strlen(a+), Lb = strlen(b+);
for(int i = ; i < ; i++) sa[i] = sb[i] = INF, ea[i] = eb[i] = ;
for(int i = ; i <= La; i++){
a[i] -= 'A';
sa[a[i]] = min(sa[a[i]], i);
ea[a[i]] = i;
}
for(int i = ; i <= Lb; i++){
b[i] -= 'A';
sb[b[i]] = min(sb[b[i]], i);
eb[b[i]] = i;
} d[][] = c[][] = ;
for(int j = , t = ; t <= La; t++, j ^= ){
for(int i = ; i <= Lb; i++){
if(!t && !i) continue; int v = INF, v2 = INF;
if(t) v = d[j^][i] + c[j^][i]; //在a[1..t-1]与b[1..i]后加a[t]
if(i) v2 = d[j][i-] + c[j][i-]; //在a[1..t]与b[1..i-1]后加b[i]
d[j][i] = min(v, v2); if(t){
c[j][i] = c[j^][i];
if(sa[a[t]] == t && sb[a[t]] > i) c[j][i]++;
if(ea[a[t]] == t && eb[a[t]] <= i) c[j][i]--;
}
else{
c[j][i] = c[j][i-];
if(sb[b[i]] == i && sa[b[i]] > t) c[j][i]++;
if(eb[b[i]] == i && ea[b[i]] <= t) c[j][i]--;
}
}
}
printf("%d\n", d[La&][Lb]);
}
return ;
}

UVa 1625 - Color Length(线性DP + 滚动数组)的更多相关文章

  1. UVA - 1625 Color Length[序列DP 代价计算技巧]

    UVA - 1625 Color Length   白书 很明显f[i][j]表示第一个取到i第二个取到j的代价 问题在于代价的计算,并不知道每种颜色的开始和结束   和模拟赛那道环形DP很想,计算这 ...

  2. UVA - 1625 Color Length[序列DP 提前计算代价]

    UVA - 1625 Color Length   白书 很明显f[i][j]表示第一个取到i第二个取到j的代价 问题在于代价的计算,并不知道每种颜色的开始和结束   和模拟赛那道环形DP很想,计算这 ...

  3. UVa 1625 Color Length

    思路还算明白,不过要落实到代码上还真敲不出来. 题意: 有两个由大写字母组成的颜色序列,将它们合并成一个序列:每次可以把其中一个序列开头的颜色放到新序列的尾部. 对于每种颜色,其跨度定义为合并后的序列 ...

  4. cf909C 线性dp+滚动数组好题!

    一开始一直以为是区间dp.. /* f下面必须有一个s 其余的s可以和任意f进行匹配 所以用线性dp来做 先预处理一下: fffssfsfs==>3 0 1 1 dp[i][j] 表示第i行缩进 ...

  5. [tyvj 1061] Mobile Service (线性dp 滚动数组)

    3月15日第一题! 题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Local 题目描述 一个公司有三个移动服务员.如果某个地方有一个请求,某个员工必须 ...

  6. UVa 1625 Color Length (DP)

    题意:给定两个序列,让你组成一个新的序列,让两个相同字符的位置最大差之和最小.组成方式只能从一个序列前部拿出一个字符放到新序列中. 析:这个题状态表示和转移很容易想到,主要是在处理上面,dp[i][j ...

  7. UVA 1625 Color Length 颜色的长度 (预处理+dp)

    dp[i][j]表示前一个序列拿了i个颜色,后一个序列拿了j个颜色的最小花费. 转移的时候显然只能向dp[i+1][j],或dp[i][j+1]转移,每增加拿走一个颜色,之前已经出现但没结束的颜色个数 ...

  8. UVA 1625 "Color Length" (基础DP)

    传送门 •参考资料 [1]:HopeForBetter •题意 •题解(by 紫书) •我的理解 用了一上午的时间,参考紫书+上述博文,终于解决了疑惑: 定义第一个颜色序列用串 s 表示,第二个用串 ...

  9. HDU 1024 Max Sum Plus Plus --- dp+滚动数组

    HDU 1024 题目大意:给定m和n以及n个数,求n个数的m个连续子系列的最大值,要求子序列不想交. 解题思路:<1>动态规划,定义状态dp[i][j]表示序列前j个数的i段子序列的值, ...

随机推荐

  1. javaweb之请求的转发和重定向

    1.什么是请求转发和请求重定向? 请求转发: xxServlet收到请求,然后直接转发给yyServlet,然后yyServlet返回给客户端.整个过程中,客户端发出一个请求,收到一个响应. 重定向: ...

  2. svn 文件后面显示时间和提交人

    1.在eclipse中选择window-->preferences,然后选择下图中的位置,就可以显示你想要的东西的了,在此记下以备后用

  3. thinkphp下判断状态值语法

    在thinkphp框架下我们经常会用到状态值的判断:但是这样写会引起语法错误. <div> <if condition="{$res.status} eq '0'" ...

  4. [翻译]Review——The Inner Workings Of Virtual DOM

    The Inner Workings Of Virtual DOM 虚拟DOM的内部工作机制 原文地址:https://medium.com/@rajaraodv/the-inner-workings ...

  5. java 从Excel 输出和输入

    本文实现了使用java 从数据库中获得对象,并存入集合中, 然后输出到Excel,并设置样式 package com.webwork; import java.io.File; import java ...

  6. 关于display:inline-block布局导致错位问题分析

    移动端设计稿需求是这样的,如下图: 未知的几个头像从左至右并行居中排列. 一般可能直接使用float,但是设计图要求头像排列始终是居中的,于是想到要让它们成为行内元素,然后可使用的方法有flex bo ...

  7. [ZOJ3316]:Game

    题面 vjudge Sol 有一个棋盘,棋盘上有一些棋子,两个人轮流拿棋,第一个人可以随意拿,以后每一个人拿走的棋子与上一个人拿走的棋子的曼哈顿距离不得超过L,无法拿棋的人输,问后手能否胜利 首先距离 ...

  8. Python-正则表达式实现计算器功能

    需求: 用户输入运算表达式,终端显示计算结果 源代码: # !/usr/bin/env/ python3 # -*- coding: utf-8 -*- """用户输入计 ...

  9. Linux基础之命令练习Day3-文件管理:cat,tar,gzip,vim,ln

    一. 文件合并 cat命令的用途是连接文件或标准输入并打印.这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用. 1.命令格式: cat [ ...

  10. 浅谈JavaScript之function用括号包起来

    (function a(){}) (命名函数表达式)会返回这个函数(不会执行),但是在括号外面无法调用该函数,需要一个变量接收这个函数,var fun = (function a(){}),一般这个用 ...