UVA 1625 "Color Length" (基础DP)
•参考资料
[1]:HopeForBetter
•题意
•题解(by 紫书)
•我的理解
用了一上午的时间,参考紫书+上述博文,终于解决了疑惑;
定义第一个颜色序列用串 s 表示,第二个用串 t 表示,下标均从 1 开始;
定义dp(i,j)表示串 s 的前 i 个字符与串 t 的前 j 个字符合并的最小值;
' ? ' 是加什么呢?
分析一下,当前的新序列包含哪些类型的字符:
1)当前新序列包含字符 ch 的开始和结束;
2)当前新序列只包含字符 ch 的开始,而不包含其结束;
3)当前新序列不包含字符 ch;
就情况①,将 si 插入到尾部后,你会发现,这个新插入的元素只会影响 1) 类型字符,怎么影响呢?
当前字符 si 的插入会使得 1) 类型的字符首尾距离增加 1;
那么,情况①中的 ' ? ' 指的就是 s 串的前 i-1 个字符与 t 串中的前 j 个字符的 1) 类型的字符个数;
情况②同理;
那么,如何求解 "s 串的前 i-1 个字符与 t 串中的前 j 个字符的 1) 类型的字符个数" 呢?
定义 w(i,j) 表示串 s 的前 i 个字符与串 t 的前 j 个字符包含的 1) 类型的字符总个数;
struct Data
{
int fir,las;
Data(int fir=INF,int las=):fir(fir),las(las){}
};
int w[maxn][maxn]; void Preset()
{
/**
a[i].fir:字符 'A'+i 在串s中第一次出现的位置
a[i].las:字符 'A'+i 在串s中最后一次出现的位置
b[i].fir:字符 'A'+i 在串t中第一次出现的位置
b[i].las:字符 'A'+i 在串t中最后一次出现的位置
*/
Data a[],b[];
for(int i=;i <= n;++i)
{
Data &tmp=a[s[i]-'A'];
tmp.fir=min(tmp.fir,i);
tmp.las=i;
}
for(int i=;i <= m;++i)
{
Data &tmp=b[t[i]-'A'];
tmp.fir=min(tmp.fir,i);
tmp.las=i;
}
w[][]=;
for(int i=;i <= n;++i)
{
for(int j=;j <= m;++j)
{
if(i)
{
w[i][j]=w[i-][j];
int k=s[i]-'A';
if(a[k].fir == i && b[k].fir > j)///判断si是否为首次出现的
w[i][j]++;
if(a[k].las == i && b[k].las <= j)///判断si是否为结尾字符
w[i][j]--;
}
if(j)
{
w[i][j]=w[i][j-];
int k=t[j]-'A';
if(b[k].fir == j && a[k].fir > i)///判断tj是否为首次出现的
w[i][j]++;
if(b[k].las == j && a[k].las <= i)///判断tj是否为结尾字符
w[i][j]--;
}
}
}
}求解w(i,j)
求解完 w(i,j) 后,状态转移方程也就完成了:
•Code
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define INFll 0x3f3f3f3f3f3f3f3f
#define ll long long
const int maxn=5e3+; int n,m;
char s[maxn];
char t[maxn];
struct Data
{
int fir,las;
Data(int fir=INF,int las=):fir(fir),las(las){}
};
int w[maxn][maxn];
ll dp[maxn][maxn]; void Preset()
{
/**
a[i].fir:字符 'A'+i 在串s中第一次出现的位置
a[i].las:字符 'A'+i 在串s中最后一次出现的位置
b[i].fir:字符 'A'+i 在串t中第一次出现的位置
b[i].las:字符 'A'+i 在串t中最后一次出现的位置
*/
Data a[],b[];
for(int i=;i <= n;++i)
{
Data &tmp=a[s[i]-'A'];
tmp.fir=min(tmp.fir,i);
tmp.las=i;
}
for(int i=;i <= m;++i)
{
Data &tmp=b[t[i]-'A'];
tmp.fir=min(tmp.fir,i);
tmp.las=i;
}
w[][]=;
for(int i=;i <= n;++i)
{
for(int j=;j <= m;++j)
{
if(i)
{
w[i][j]=w[i-][j];
int k=s[i]-'A';
if(a[k].fir == i && b[k].fir > j)///判断si是否为首次出现的
w[i][j]++;
if(a[k].las == i && b[k].las <= j)///判断si是否为结尾字符
w[i][j]--;
}
if(j)
{
w[i][j]=w[i][j-];
int k=t[j]-'A';
if(b[k].fir == j && a[k].fir > i)///判断tj是否为首次出现的
w[i][j]++;
if(b[k].las == j && a[k].las <= i)///判断tj是否为结尾字符
w[i][j]--;
}
}
}
}
ll Solve()
{
Preset();
dp[][]=;
for(int i=;i <= n;++i)
{
for(int j=;j <= m;++j)
{
if(!(i+j))
continue;
dp[i][j]=INFll; if(i)
dp[i][j]=min(dp[i][j],dp[i-][j]+w[i-][j]);
if(j)
dp[i][j]=min(dp[i][j],dp[i][j-]+w[i][j-]);
}
}
return dp[n][m];
}
int main()
{
int test;
scanf("%d",&test);
while(test--)
{
scanf("%s%s",s+,t+);
n=strlen(s+);
m=strlen(t+); printf("%lld\n",Solve());
}
return ;
}
UVA 1625 "Color Length" (基础DP)的更多相关文章
- UVA - 1625 Color Length[序列DP 代价计算技巧]
UVA - 1625 Color Length 白书 很明显f[i][j]表示第一个取到i第二个取到j的代价 问题在于代价的计算,并不知道每种颜色的开始和结束 和模拟赛那道环形DP很想,计算这 ...
- UVA - 1625 Color Length[序列DP 提前计算代价]
UVA - 1625 Color Length 白书 很明显f[i][j]表示第一个取到i第二个取到j的代价 问题在于代价的计算,并不知道每种颜色的开始和结束 和模拟赛那道环形DP很想,计算这 ...
- UVa 1625 - Color Length(线性DP + 滚动数组)
链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- UVa 1625 Color Length (DP)
题意:给定两个序列,让你组成一个新的序列,让两个相同字符的位置最大差之和最小.组成方式只能从一个序列前部拿出一个字符放到新序列中. 析:这个题状态表示和转移很容易想到,主要是在处理上面,dp[i][j ...
- UVA 1625 Color Length 颜色的长度 (预处理+dp)
dp[i][j]表示前一个序列拿了i个颜色,后一个序列拿了j个颜色的最小花费. 转移的时候显然只能向dp[i+1][j],或dp[i][j+1]转移,每增加拿走一个颜色,之前已经出现但没结束的颜色个数 ...
- UVa 1625 Color Length
思路还算明白,不过要落实到代码上还真敲不出来. 题意: 有两个由大写字母组成的颜色序列,将它们合并成一个序列:每次可以把其中一个序列开头的颜色放到新序列的尾部. 对于每种颜色,其跨度定义为合并后的序列 ...
- 动态规划(模型转换):uvaoj 1625 Color Length
[PDF Link]题目点这里 这道题一眼就是动态规划,然而貌似并不好做. 如果不转换模型,状态是难以处理的. 巧妙地转化:不直接求一种字母头尾距离,而是拆开放到状态中. #include <i ...
- UVA 12405 Scarecrow (基础DP)
题意: 给出一个1*N的矩阵(就是一行的格子),其中部分格子可以有草,部分无草,现在要求放置一些稻草人在某些格子上,每个稻草人可以覆盖3个连续格子,为使得有草的格子都能被覆盖,问最少放置几个稻草人. ...
- UVA 10037 Bridge (基础DP)
题意: 过河模型:有n个人要渡河,每个人渡河所耗时可能不同,只有1只船且只能2人/船,船速取决于速度慢的人.问最少耗时多少才能都渡完河? 思路: n<2的情况比较简单. 考虑n>2的情况, ...
随机推荐
- P1127
题目描述 如果单词X的末字母与单词Y的首字母相同,则X与Y可以相连成X.Y.(注意:X.Y之间是英文的句号“.”).例如,单词dog与单词gopher,则dog与gopher可以相连成dog.goph ...
- 廖雪峰Python总结4
面向对象编程 将计算机程序视为一系列的命令集合.包含: 数据 操作数据的函数 Python中,所有的数据类型都可以视为对象. 面向对象特点:封装,继承,多态. 类的函数和普通函数:类的第一个参数永远是 ...
- laravel 分页带参数
{{$data->appends(request()->except(['page']))->links()}}
- es6中的(=>)箭头函数
x => x * x 上面的箭头函数相当于: function (x) { return x * x; } 箭头函数相当于匿名函数,并且简化了函数定义. 箭头函数有两种格式,一种像上面的,只包含 ...
- Leetcode784.Letter Case Permutation字母大小写全排列
给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串.返回所有可能得到的字符串集合. 示例: 输入: S = "a1b2" 输出: ["a1 ...
- Ubuntu18.04+windows10双系统时间同步教程
前言: 系统安装windows10和Ubuntu18.04双系统后会出现时间不同步的情况,往往windows系统的时间会有错误,一般会有8个小时的误差. 原因: 主要因为本地时间与硬件时间的时差: 本 ...
- Python2 生成器 简介
1. A generator: provide a kind of function that can return an intermediate result ("the next va ...
- Oracle使用——PLSQL查询表结构并导出EXCEL
背景 有一次需要查询Oracle数据库中的所有表接口并且导出excel,方法记录如下 使用 使用PLSQL工具查询表结构,SQL语句如下 SELECT B.TABLE_NAME AS '表名', C. ...
- Java面向对象----Java面向对象(OOP)概念
理解面向对象 关键:让每一个对象负责执行一组相关任务 面向过程:算法第一,数据第二 面向对象:数据第一,算法第一 特点: 万物皆对象 程序是一组对象彼此之间在发送消息 每个对象都有自己的内存占用,可以 ...
- [React Native]访问操作系统剪贴板 Clipboard
我们之前学习了TextInput组件, 有时候我们需要在TextInput组件中复制或者粘贴一些文字. React Native为开发者提供了 Clipboard API,Clipboard 组件可以 ...



