传送门

•参考资料

  [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)的更多相关文章

  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(线性DP + 滚动数组)

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

  4. UVa 1625 Color Length (DP)

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

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

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

  6. UVa 1625 Color Length

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

  7. 动态规划(模型转换):uvaoj 1625 Color Length

    [PDF Link]题目点这里 这道题一眼就是动态规划,然而貌似并不好做. 如果不转换模型,状态是难以处理的. 巧妙地转化:不直接求一种字母头尾距离,而是拆开放到状态中. #include <i ...

  8. UVA 12405 Scarecrow (基础DP)

    题意: 给出一个1*N的矩阵(就是一行的格子),其中部分格子可以有草,部分无草,现在要求放置一些稻草人在某些格子上,每个稻草人可以覆盖3个连续格子,为使得有草的格子都能被覆盖,问最少放置几个稻草人. ...

  9. UVA 10037 Bridge (基础DP)

    题意: 过河模型:有n个人要渡河,每个人渡河所耗时可能不同,只有1只船且只能2人/船,船速取决于速度慢的人.问最少耗时多少才能都渡完河? 思路: n<2的情况比较简单. 考虑n>2的情况, ...

随机推荐

  1. HTML-DOM常用对象的用法(select/option/form/table)

    HTML DOM 常用对象: 它对常用HTML元素操作的简化. Select对象 它代表页面上的一个select元素,常用属性有: select.value ——当前选中项的value ,没有valu ...

  2. linux下的OpenCV安装&学习笔记

    http://www.linuxdiyf.com/viewarticle.php?id=20731 (本想在fedora下安装编译的,但目前opencv官网.sourceforge等网站都无法访问下载 ...

  3. JavaScript--tab栏切换效果

    tab栏切换效果: <!DOCTYPE html> <html> <head lang="en"> <meta charset=" ...

  4. HDU 4193

    本题思路:用sum[]数组维护前缀和, 当然这里需要把原数组扩大为原来的两倍. 然后对于任意一个长度为n的区间 k.....k+n-1,如果有该区间内的最小值大于等于sum[k-1]那么该种情况就符合 ...

  5. Linux配置redis开机启动(CentOS 7)

    https://blog.csdn.net/qq_31803503/article/details/79246205 本次配置linux版本是CentOS 7 首先将  redis-3.2.3/uti ...

  6. KiCad 安装后没有元件怎么办?

    KiCad 安装后没有元件怎么办? 按以下步骤试试. 卸载 KiCad EDA. 按 Win+R 输入 %appdata%/kicad 进入 KiCad 的配置目录. 将里面的内容打包成一个 zip ...

  7. 当async/await碰见forEach-------------爆炸

    let p = ['http://img3.imgtn.bdimg.com/it/u=3278834702,2663618759&fm=26&gp=0.jpg', 'http://im ...

  8. Redis源码解析:07压缩列表

    压缩列表(ziplist)是列表键和哈希键的底层实现之一.当列表键只包含少量列表项,并且每个列表项要么是小整数值,要么是长度较短的字符串时:或者当哈希键只包含少量键值对,并且每个键值对的键和值要么是小 ...

  9. Python基础:16面向对象概述

    1:在版本2.2 中,Python社区最终统一了类型(type)和类(class),新式类具备更多高级的OOP特性,扮演了一个经典类(旧式类)超集的角色,后者是Python 诞生时所创造的类对象. 2 ...

  10. Spring IoC 使用详解

    在Spring中,依赖注入(DI)模式实现了控制反转(IoC)原理.让我们通过一个例子来帮助理解依赖注入.我们先看到java版的例子,然后在此基础上加上spring的功能.就例子而言,是相当地简单.Q ...