CF10D/POJ2127 LCIS解题报告
前言
期末考试前的最后一篇题解,希望期末考 rp++
奇怪,为什么在CF上能过的代码到POJ上就 听取WA声一片 (不管了)
题目思路
LCIS模版O(n²)+方案记录(递归输出)
LCIS
基础方法
简单易想的方法:直接将LCS和LIS简单相加,复杂度O(n³)
for (int i = 1; i <= l1; i++)
for (int j = 1; j <= l2; j++)
if (a[i] == b[j]) {
for (int k = 0; k < j; k++)
if (b[k] < a[i])
f[i][j] = max (f[i][j], f[i-1][k] + 1);
}
else f[i][j] = f[i-1][j];
时间优化dp
不难看出,状态转移的时候 f 数组的第一维都是由 i-1 转移过来的, 所以不必枚举每一个 k,可以用一个数把之前的最佳方案记录下来
当 i,j 满足a[i] > b[j]时,f[i-1][j]可以去更新最优方案 (因为b[j] < a[i] 时,可以构成上升序列)
#define f(i,a,b) for (int i = a; i <= b; i++)
f (i, 1, l1){
int tmp(0); //tmp记录最优解的值
f (j, 1, l2){
f[i][j] = f[i-1][j];
if (a[i] > b[j]) tmp = max (tmp, f[i-1][j]); //如果满足条件,更新最优方案
if (a[i] == b[j]) f[i][j] = tmp + 1; //如果两个数相等,答案为之前的最优情况+1
ans = max (ans, f[i][j]);
}
}
空间优化dp
因为状态转移的时候 f 数组的第一维都是由 i-1 转移过来的,所以不但在时间上可以记录最优策略来优化,空间上也可以省去第一维。
在代码实现时直接将数组第一维删去即可
#define f(i,a,b) for (int i = a; i <= b; i++)
f (i, 1, l1){
int tmp(0); //tmp记录最优解的值
f (j, 1, l2){
if (a[i] > b[j] ) tmp = f[j]; //如果满足条件,更新最优方案
if (a[i] == b[j]) f[j] = tmp + 1;
//如果两个数相等,答案为之前的最优情况+1
ans = max (ans, f[j]);
}
}
路径记录
基础方法
用一个数组 w[i][j] 来表示 f[i][j] 以 b[j] 为结尾的方案的序列的上一个数的位置。
例如样例中,样例输出 3 5 6 中,以 6 为结尾的方案的 w 数组中存的就是数字 5 的位置
#define f(i,a,b) for (int i = a; i <= b; i++)
f (i, 1, l1){
int tmp(0), k(0); //tmp记录最优解的值,k记录位置
f (j, 1, l2){
f[i][j] = f[i-1][j], w[i][j] = w[i-1][j];
if (a[i] > b[j] and f[i-1][j] > tmp)
tmp = f[i-1][j], k = j; //如果满足条件,更新最优方案
if (a[i] == b[j]) f[i][j] = tmp + 1, w[i][j] = k;
//如果两个数相等,答案为之前的最优情况+1,w 改为记录的最优方案的上一个位置
ans = max (ans, f[i][j]);
}
}
空间优化
和上面求解LCIS的最长长度的空间优化一样,w 数组的第一维在状态转移的时候,i 都是由 i-1 转移过来的,因此也可以去掉一维
#define f(i,a,b) for (int i = a; i <= b; i++)
f (i, 1, l1){
int tmp(0), k(0); //tmp记录最优解的值,k记录位置
f (j, 1, l2){
if (a[i] > b[j] and f[j] > tmp)
tmp = f[j], k = j; //如果满足条件,更新最优方案
if (a[i] == b[j]) f[j] = tmp + 1, w[j] = k;
//如果两个数相等,答案为之前的最优情况+1,w 改为记录的最优方案的上一个位置
ans = max (ans, f[j]);
}
}
方案输出
输出时先枚举每一个以 b[j] 结尾的答案与最优解对比,从而找出最优解的最后一个数(注意:要特判答案是否存在长度>0的序列,若没有不用输出,我为此WA了两次)
if (ans) //特判是否存在长度>0的序列
f (i, 1, l2)
if (f[l1][i] == ans) {print(i); break;} //找到最优解的末尾位置并输出序列
找到位置后递归输出
void print (int p) {
if (w[l1][p]) print(w[l1][p]); //如果之前还有数,先输出之前的数
printf ("%d ", b[p]);
}
优化效果

可以看出,优化后空间极其节省(虽然两种都能过)
至于时间上的差异emm······ 连续交两次同样代码跑出来的时间都差好多
完整代码
未优化
#include <cstdio>
#include <iostream>
using namespace std;
#define f(i,a,b) for (register int i = a; i <= b; i++)
int l1, l2, a[538], b[538], f[538][538], w[538][538], ans;
void print (int p) {
if (w[l1][p]) print(w[l1][p]); //如果之前还有数,先输出之前的数
printf ("%d ", b[p]);
}
int main() {
scanf ("%d", &l1);
f (i, 1, l1) scanf ("%d", a + i);
scanf ("%d", &l2);
f (i, 1, l2) scanf ("%d", b + i);
f (i, 1, l1){
int tmp(0), k(0); //tmp记录最优解的值,k记录位置
f (j, 1, l2){
f[i][j] = f[i-1][j], w[i][j] = w[i-1][j];
if (a[i] > b[j] and f[i-1][j] > tmp)
tmp = f[i-1][j], k = j; //如果满足条件,更新最优方案
if (a[i] == b[j]) f[i][j] = tmp + 1, w[i][j] = k;
//如果两个数相等,答案为之前的最优情况+1,w 改为记录的最优方案的上一个位置
ans = max (ans, f[i][j]);
}
}
printf ("%d\n", ans);
if (ans) //特判是否存在长度>0的序列
f (i, 1, l2)
if (f[l1][i] == ans) {print(i); break;} //找到最优解的末尾位置并输出序列
return 0;
}
优化后
#include <cstdio>
#include <iostream>
using namespace std;
#define f(i,a,b) for (register int i = a; i <= b; i++)
int l1, l2, a[538], b[538], f[538], w[538], ans;
void print (int p) {
if (w[p]) print(w[p]); //如果之前还有数,先输出之前的数
printf ("%d ", b[p]);
}
int main() {
scanf ("%d", &l1);
f (i, 1, l1) scanf ("%d", a + i);
scanf ("%d", &l2);
f (i, 1, l2) scanf ("%d", b + i);
f (i, 1, l1){
int tmp(0), k(0); //tmp记录最优解的值,k记录位置
f (j, 1, l2){
if (a[i] > b[j] and f[j] > tmp)
tmp = f[j], k = j; //如果满足条件,更新最优方案
if (a[i] == b[j]) f[j] = tmp + 1, w[j] = k;
//如果两个数相等,答案为之前的最优情况+1,w 改为记录的最优方案的上一个位置
ans = max (ans, f[j]);
}
}
printf ("%d\n", ans);
if (ans) //特判是否存在长度>0的序列
f (i, 1, l2)
if (f[i] == ans) {print(i); break;} //找到最优解的末尾位置并输出序列
return 0;
}
CF10D/POJ2127 LCIS解题报告的更多相关文章
- CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
- BZOJ 1051 最受欢迎的牛 解题报告
题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ...
- 习题:codevs 2822 爱在心中 解题报告
这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...
- 习题:codevs 1035 火车停留解题报告
本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...
- 习题: codevs 2492 上帝造题的七分钟2 解题报告
这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHS ...
- 习题:codevs 1519 过路费 解题报告
今天拿了这道题目练练手,感觉自己代码能力又增强了不少: 我的思路跟别人可能不一样. 首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这 ...
- NOIP2016提高组解题报告
NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合
- LeetCode 解题报告索引
最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中...... ...
随机推荐
- IpIImage -> CvMat 转换方法
Ipl转为CvMat 一般为这两种方法: 1: /*cvGetMat*/ CvMat matheader; CvMat * mat = cvGetMat(img, &matheader); 2 ...
- Postgresql windows下安装过程
1.下载前三个软件: 理论上安装Perl,TCL,Bison and Flex这三个插件 实际上安装ActiveState Perl,ActiveState tcl ,MinGW 因为MinGW包括了 ...
- linux命令学习笔记(58):telnet命令
telnet命令通常用来远程登录.telnet程序是基于TELNET协议的远程登录客户端程序.Telnet协议是TCP/IP协议族 中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用 ...
- git branch detached from jb4.2.2_1.0.0-ga
/*************************************************************************** * git branch detached f ...
- 1045 Favorite Color Stripe (30)(30 分)
Eva is trying to make her own color stripe out of a given one. She would like to keep only her favor ...
- 洛谷 P1187 3D模型
题目描述 一座城市建立在规则的n×m网格上,并且网格均由1×1正方形构成.在每个网格上都可以有一个建筑,建筑由若干个1×1×1的立方体搭建而成(也就是所有建筑的底部都在同一平面上的).几个典型的城市模 ...
- P1731 生日蛋糕
题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱 ...
- DevExpress 显示进度条
1.使用了DevExpress的WaitDialogForm WaitDialogForm waitDialogForm = null; new Thread((ThreadStart)delegat ...
- 0010_while循环
while 条件: 代码块 break:跳出循环语句 continue:跳出本次循环,进入下一次循环. __author__ = 'qq593' #!/usr/bin/env python #-*- ...
- Matlab数据类型的转换
Matlab中有15种基本数据类型,主要是整型.浮点.逻辑.字符.日期和时间.结构数组.单元格数组以及函数句柄等. 1.整型:(int8:uint8:int16:uint16:int32:uint32 ...