题目传送门(洛谷)(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. BEC listen and translation exercise 33

    In fact, if it is a really hot day, like the sort of weather we had last summer, you are advised to ...

  2. 判断浏览器是否支持css3属性或单位

    1.用CSS.supports()方法 mark-zhq[3] //判断是否支持flex布局 var supportsFlex = CSS.supports("display", ...

  3. 优秀开源项目之二:流媒体直播系统Open Broadcaster Software

    Open Broadcaster Software(OBS)是一款用于音视频录制和直播的免费开源软件.可以轻松部署到多种平台,目前支持Windows.MAC和Linux. 特性: 1.高性能的实时视频 ...

  4. 多媒体的框架 - OpenCore框架概述

    OpenCore是一个多媒体的框架,从宏观上来看,它主要包含了两大方面的内容:PVPlayer:提供媒体播放器的功能,完成各种音频 (Audio).视频(Video)流的回放(Playback)功能. ...

  5. iOS NET Error Code

    see NSURLError.h Define NSURLErrorUnknown = -, NSURLErrorCancelled = -, NSURLErrorBadURL = -, NSURLE ...

  6. Android的缓存图片不在系统图库中显示的解决办法

    Android的图库会在开机的时候扫描SD卡中的图片,视频等文件,有很多App的私有图片不想在图库中显示,就需要另外处理了. 解决办法:在缓存图片的文件夹中创建 .nomedia 文件. 1. &qu ...

  7. POJ1379:Run Away

    我对模拟退火的理解:https://www.cnblogs.com/AKMer/p/9580982.html 我对爬山的理解:https://www.cnblogs.com/AKMer/p/95552 ...

  8. TextBlock截断字符显示为....

    添加: TextTrimming="CharacterEllipsis" 到TextBlock中, 即可让TextBlock 支持截断字符显示为...

  9. spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入

    <spring扩展点之二:spring中关于bean初始化.销毁等使用汇总,ApplicationContextAware将ApplicationContext注入> <spring ...

  10. [HDU3037]Saving Beans,插板法+lucas定理

    [基本解题思路] 将n个相同的元素排成一行,n个元素之间出现了(n-1)个空档,现在我们用(m-1)个“档板”插入(n-1)个空档中,就把n个元素隔成有序的m份,每个组依次按组序号分到对应位置的几个元 ...