最长不下降子序列 nlogn && 输出序列
最长不下降子序列实现:
利用序列的单调性。
对于任意一个单调序列,如 1 2 3 4 5(是单增的),若这时向序列尾部增添一个数 x,我们只会在意 x 和 5 的大小,若 x>5,增添成功,反之则失败。由于普通代码是从头开始比较,而 x 和 1,2,3,4 的大小比较是没有用处的,这种操作只会造成时间的浪费,所以效率极低。对于单调序列,只需要记录每个序列的最后一个数,每增添一个数 x,直接比较 x 和末尾数的大小。只有最后一个数才是有用的,它表示该序列的最大限度值。
实现方法就是新开一个数组 d,用它来记录每个序列的末尾元素,以求最长不下降为例,d[k] 表示长度为k的不下降子序列的最小末尾元素。
我们用 len 表示当前凑出的最长序列长度,也就是当前 d 中的最后那个位置。
这样就很 easy 了,每读入一个数 x,如果 x 大于等于 d[len],直接让 d[len+1]=x,然后 len++,相当于把 x 接到了最长的序列后面;
如果 x 小于 d[len],说明 x 不能接到最长的序列后面,那就找 d[1...len−1] 中末尾数小于等于 x 的的序列,然后把 x 接到它后面。举个例子,若当前 x==7,len==8:
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
2 |
3 |
4 |
7 |
7 |
10 |
12 |
29 |
d[1]⋯d[5] 均小于等于 x,若在 d[1] 后接 x,则 d[2] 应换成 x,但 d[2]==3,比 x 小,能接更多的数,用 7 去换 3 显然是不划算的,所以 x 不能接 d[1] 后。同理,d[2]⋯d[4] 均不能接x。由于 d[5]≤x 且 x<d[6],7 能比 10 接更多的数,所以选择在 d[5] 后接 x,用 x 替换 10。
根据这个操作过程,易知数组 d 一定是单调的序列,所以查找的时候可以用二分!二分效率是 logn 的,所以整个算法的效率就是 nlogn 的啦~
输出序列实现:
想了好久,认为 nlogn 做法也是可以输出序列的,这时候需要增加一个 c 数组 用来记录每个元素在最长序列中的位置,即 c[i] 表示 a[i] 被放到了序列的第几个位置。
输出时,从 数组 a 的尾部开始,逆序依次找出 c 为 len, len-1, len-2 … 3, 2, 1 的元素,并且找到一个就接着寻找 c[i]-1,直到找到 c[i] 为 1 的数。
举个例子:
a: | 13 | 7 | 9 | 16 | 38 | 24 | 37 | 18 | 44 | 19 | 21 | 22 | 63 | 15 |
c: | 1 | 1 | 2 | 3 | 4 | 4 | 5 | 4 | 6 | 5 | 6 | 7 | 8 | 3 |
len = 8;
我们从 15 开始倒着找 c 为 8 的元素,找到 63,接着找 c 为 7 的,找到 22,再找 c 为 6 的,找到 21,再找 c 为 5 …… 以此类推。
从而,我们得出的序列为 63,22,21,19,18,16,9,7
逆序输出来,就是 7,9,16,18,19,21,22,63
为什么这个方法是对的呢?倒序查找保证了两个条件:
- 如果 c 中有多个相同的数,后面的一定是最新更新的;
- 在保证一条件的前提下,倒序找,后面的数一定可以接到前面数的后面。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define int long long
#define maxn 1000+10
using namespace std;
inline int read()
{
int x=;
bool f=;
char c=getchar();
for(; !isdigit(c); c=getchar()) if(c=='-') f=;
for(; isdigit(c); c=getchar()) x=(x<<)+(x<<)+c-'';
if(f) return x;
return -x;
}
inline void write(int x)
{
if(x<){putchar('-');x=-x;}
if(x>)write(x/);
putchar(x%+'');
}
int n,len;
int a[maxn],last[maxn],site[maxn];
stack<int> s;
signed main()
{
n=read();
for(int i=;i<=n;i++) a[i]=read();
if(n==)
{
write();
return ;
}
len=;
last[]=a[];
site[]=;
for(int i=;i<=n;i++)
{
if(a[i]>=last[len])
{
last[++len]=a[i];
site[i]=len;
}
else
{
int now=lower_bound(last+,last+len+,a[i])-last;
last[now]=a[i];
site[i]=now;
}
}
printf("max=");
write(len);
printf("\n");
for(int i=n,j=len;i>=;i--)
{
if(site[i]==j)
{
s.push(a[i]);
j--;
}
if(j==) break;
}
while(!s.empty())
{
int put=s.top();
s.pop();
write(put);
printf(" ");
}
return ;
}
请各位大佬斧正(反正我不认识斧正是什么意思)
最长不下降子序列 nlogn && 输出序列的更多相关文章
- 最长不下降子序列nlogn算法详解
今天花了很长时间终于弄懂了这个算法……毕竟找一个好的讲解真的太难了,所以励志我要自己写一个好的讲解QAQ 这篇文章是在懂了这个问题n^2解决方案的基础上学习. 解决的问题:给定一个序列,求最长不下降子 ...
- hdu1025 最长不下降子序列nlogn算法
C - DP Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:32768KB 64bit I ...
- 最长不下降子序列nlogn
b[i]表示长度为i的最长不下降子序列的最小末尾元素的值显然它是单调递增的,满足二分性质,然后就可以愉快地二分啦. #include<iostream> #include<cstdi ...
- 最长不下降子序列(线段树优化dp)
最长不下降子序列 题目大意: 给定一个长度为 N 的整数序列:A\(_{1}\),A\(_{2}\),⋅⋅⋅,A\(_{N}\). 现在你有一次机会,将其中连续的 K 个数修改成任意一个相同值. 请你 ...
- tyvj 1049 最长不下降子序列 n^2/nlogn
P1049 最长不下降子序列 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 求最长不下降子序列的长度 输入格式 第一行为n,表示n个数第二行n个数 输出格式 ...
- 最长不下降子序列的O(n^2)算法和O(nlogn)算法
一.简单的O(n^2)的算法 很容易想到用动态规划做.设lis[]用于保存第1~i元素元素中最长不下降序列的长度,则lis[i]=max(lis[j])+1,且num[i]>num[j],i&g ...
- 最长不下降子序列//序列dp
最长不下降子序列 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 求最长不下降子序列的长度 输入格式 第一行为n,表示n个数第二行n个数 输出格式 最长不下降 ...
- P1020 导弹拦截(nlogn求最长不下降子序列)
题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...
- hdu 1160 FatMouse's Speed(最长不下降子序列+输出路径)
题意: FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to ...
随机推荐
- C++类的组合、前向引用声明
3.5类的组合 Part1.应用背景 对于复杂的问题,往往可以逐步划分为一系列稍微简单的子问题. 解决复杂问题的有效方法是将其层层分解为简单的问题组合,首先解决简单问题复杂问题也就迎刃而解了. 在面向 ...
- golang ---网卡信息
package main import ( "fmt" "log" "net" "strings" ) type Net ...
- java之hibernate之单向的一对多关联映射
这篇主要讲hiberante中的 单向一对多关联映射 1.在应用中,有时候需要从一的一端获取多的一端的数据.比如:查看某个分类下的所有书籍信息:查看某个订单下的所有商品等. 2.在一对多的关联关系中, ...
- 【SP1716】GSS3 - Can you answer these queries III(动态DP)
题目链接 之前用线段树写了一遍,现在用\(ddp\)再写一遍. #include <cstdio> #define lc (now << 1) #define rc (now ...
- Flutter裁剪图片
最近在学习中需要用到裁剪图片,记录一下解决方法 思路: 使用canvas的drawImageRect()方法,对Image进行裁剪,这里的Image需要 'dart:ui' 库中的Image. 1. ...
- 【转载】Javascript使用Math.floor方法向下取整
在Javascript的数值运算中,很多时候需要对最后计算结果向下取整,Math.floor是javascript中对计算结果向下取整的函数,它总是将数值向下舍入为最接近的整数.此外Math.ceil ...
- 手写DAO框架(六)-框架使用示例
一.引入pom <dependency> <groupId>me.lovegao</groupId> <artifactId>gdao</arti ...
- React Native 开发豆瓣评分(六)添加字体图标
添加依赖 yarn add react-native-vector-icons Link 依赖 react-native link react-native-vector-icons 使用默认字体图标 ...
- webpack4 从零学习常用配置梳理
webpack 的核心价值就是前端源码的打包,即将前端源码中每一个文件(无论任何类型)都当做一个 pack ,然后分析依赖,将其最终打包出线上运行的代码.webpack 的四个核心部分 entry 规 ...
- 如何使用jenkins部署maven父子工程
最近使用jenkins自动部署项目时遇到一个问题,如果部署单个的maven工程,没有什么问题, 但是在部署maven创建的父子工程,如果只从svn或者git上拉取子工程源码时,会报找不到父 工程pom ...