题目传送门(洛谷)(CF)(POJ)

前言

期末考试前的最后一篇题解,希望期末考  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解题报告的更多相关文章

  1. CH Round #56 - 国庆节欢乐赛解题报告

    最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...

  2. 二模13day1解题报告

    二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...

  3. BZOJ 1051 最受欢迎的牛 解题报告

    题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4438  Solved: 2353[S ...

  4. 习题:codevs 2822 爱在心中 解题报告

    这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...

  5. 习题:codevs 1035 火车停留解题报告

    本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...

  6. 习题: codevs 2492 上帝造题的七分钟2 解题报告

    这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHS ...

  7. 习题:codevs 1519 过路费 解题报告

    今天拿了这道题目练练手,感觉自己代码能力又增强了不少: 我的思路跟别人可能不一样. 首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这 ...

  8. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  9. LeetCode 解题报告索引

    最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中......                        ...

随机推荐

  1. leetcode 226. Invert Binary Tree(递归)

    Invert a binary tree. 4 / \ 2 7 / \ / \ 1 3 6 9 to 4 / \ 7 2 / \ / \ 9 6 3 1 Trivia:This problem was ...

  2. 表达式计算-----------eval()运算符

    1.java的eval()方法(或称之为运算符)可以将字符串解析成可以运行的javaScript代码,例如 eval()只有一个参数.如果传入的参数不是一个字符串,那么它会直接返回这个参数.如果传入的 ...

  3. 通过rtmpdump推送海康视频流到red5服务器

    现在主流的网络摄像机都支持标准H264视频格式,例如 海康网络摄像机, 通过海康提供的网络SDK可以获取到视频码流.我测试的这款相机,视频编码采用的是H264,音频编码采用的是G711a. 这里,我仅 ...

  4. Unity3D中的Coroutine及其使用(延时、定时调用函数)

    http://blog.csdn.net/nizihabi/article/details/47606887 一.Coroutine(协程)的概念和本质 在网上的一些资料当中,一直将Coroutine ...

  5. box head上身旋转问题

    现有资源: 1.可旋转上身的动画,旋转角度左右各90度. 2.下身没有旋转动画(腿部左转右转动画) 使用场景: 1.整个模型随鼠标位置旋转,不使用上身旋转动画. 缺点:人物转向动画僵硬.  解决方案: ...

  6. 采用MySQL_upgrade升级授权表方式升级

    1.7.1 采用MySQL_upgrade升级授权表方式升级(1) 这种升级方式比较省事,通过MySQL_upgrade命令即可完成.下面来演示一下整个升级过程. 1)修改my.cnf配置文件,因为M ...

  7. NetScaler VPX在Azure上的部署(二)

    本文是Citrix的工程师协助完成.主要是Citrix的VPX的配置. 导入License   进入NetScaler 中点击管理许可   导入后将有提示,请确认重启.   配置Azure HA 由于 ...

  8. 【转】 Pro Android学习笔记(六四):安全和权限(1):签发apk

    目录(?)[-] Android安全模型 数字证书签发 Debug的keystore 生产unsigned的apk 为apk进行证书签发 align安装包 使用Export Wizard生成签发的ap ...

  9. mac tree 命令

    mac下默认是没有 tree命令的,不过我们可以使用find命令模拟出tree命令的效果,如显示当前目录的 tree 的命令: find . -print | sed -e 's;[^/]*/;|__ ...

  10. Android开发者学习必备:10个优质的源码供大家学习

    最近看了一些开发的东西,汇总了一些源码.希望可以给大家有些帮助! 1.Android 源码解析—PagerSlidingTabStrippagerSlidingTabStrip 实现联动效果的原理是, ...