传送门

•参考资料

  [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. 洛谷P1541 乌龟棋 [2010NOIP提高组]

    P1541 乌龟棋 题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家 ...

  2. BZOJ 4420二重镇题解

    链接 思路借鉴了这个博客: 我们可以想到状压dp 用一个十进制数来表示状态,即第i位表示位置i处的物品等级 用f[i][j][k]表示第i天,仓库的物品等级为j,状态为k时的最大收益 但是状态数貌似很 ...

  3. onethink二级导航调用

    <ul class="nav-main">//添加tree参数 <think:nav name="nav" tree="true&q ...

  4. 并发模式与 RPS 模式之争,性能压测领域的星球大战

    本文是<如何做好性能压测>系列专题分享的第四期,该专题将从性能压测的设计.实现.执行.监控.问题定位和分析.应用场景等多个纬度对性能压测的全过程进行拆解,以帮助大家构建完整的性能压测的理论 ...

  5. Hdu 1007 最近点对

    题目链接 Quoit Design Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  6. Python的bisect模块

    Python的列表(list)类型内部是一个线性表,在线性表中查找元素复杂度为O(N),即调用list.index()的复杂的是O(N).当数据量较大时,应该使用二分查找优化,二分查找范围每次缩小一般 ...

  7. maven的配置和使用

    Maven 简介 1.1 Maven 是什么 翻译为“专家”,“内行” Maven是跨平台的项目管理工具.主要服务于基于Java平台的项目构建,依赖管理和项目信息管理. 1.2 为什么使用Maven ...

  8. python 只导入某个对象

  9. bzoj1800 飞行棋

    脑筋急转弯. 提示:矩形矩形矩形.O(n)O(n)O(n). 再提示:直角. 再提示:直径. 代码: //Serene #include<algorithm> #include<io ...

  10. lower_bounder()和upper_bound()的函数

    lower_bound() .upper_bound()都运用于有序区间的二分查找. ForwardIter lower_bound(ForwardIter first, ForwardIter la ...