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,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中...... ...
随机推荐
- poj-2420 A Star not a Tree?(模拟退火算法)
题目链接: A Star not a Tree? Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 5219 Accepte ...
- 06 - Django应用第三步
知识点 1) 编写urls 配合include()的URL查找过程 获取正则抓取的值并命名, 给url取名 2) 模板的编写 for循环的遍历 用点的方式执行函数, 不带括号 3) 视图函数的编写 H ...
- 【leetcode刷题笔记】Construct Binary Tree from Preorder and Inorder Traversal
Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...
- linux命令学习(8):mv命令
版权声明更新:2017-05-12博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1 文章介绍 本文介绍了Linux下面的mv命令. 2. ...
- POJ1995:Raising Modulo Numbers
二进制前置技能:https://www.cnblogs.com/AKMer/p/9698694.html 题目传送门:http://poj.org/problem?id=1995 题目就是求\(\su ...
- Brunch with a Friend 与朋友共进午餐
brownies 核仁巧克力饼 toast 烤面包 dining room 餐厅 practical 实用的 meal 一餐 combination 组合 pancake 薄煎饼 waffle 华夫饼 ...
- MyEclipse、Eclipse SVN插件的帐号、密码修改
问题描述: Eclipse的SVN插件Subclipse做得很好,在svn操作方面提供了很强大丰富的功能.但到目前为止,该插件对svn用户的概念极为淡薄,不但不能方便地切换用户,而且一旦用户的帐号.密 ...
- Java父类构造器的讲解
众所周知,对于Java中的所有类而言,它们有一个根父类,即java.lang.Object类. 对于Java中构造器执行的顺序而言,程序执行的顺序为,先执行父类的非静态代码块,然后执行父类的相应的构造 ...
- 三 akka学习 actor的例子
(转载: http://blog.csdn.net/chenleixing/article/details/44044243 ) Java并发编程的4种风格:Threads,Executors,For ...
- shell入门-变量
shell变量分为系统变量和用户自定义变量 查看变量的命令 #env 系统变量 或者 #set 包括env和自定义变量和额外变量 使用变量的命令是 #echo $[变量] //// ...