浅谈\(DP\):https://www.cnblogs.com/AKMer/p/10437525.html

题目传送门:https://www.luogu.org/problemnew/show/AT2827

\(LIS\)就是\(Longest\) \(Increasing\) \(Subsequence\),最长上升子序列问题。

给你一个序列\(a\),要你求最长上升子序列的长度。

我们可以把序列看做是一个个插数到序列尾部形成的,那么每插入一个新的数字,就是一个新的阶段。我们可以考虑用这个新插入的数字来做上升子序列的结尾,这个上升子序列会有多长。由于每次插入新的数字我们要做的事情都是一样的,所以这个问题就具有子问题重复性。由于我用这个新的数字结尾并不会影响到以以前数字结尾的子序列的长度,所以这个问题满足无后效性。并且,以当前这个数字为结尾的子序列的长度可以由在它之前的比它小的数字结尾的子序列长度得到,所以这个问题满足最优子结构性。于是我们就可以用\(DP\)来做了。

我们可以设立状态\(f_i\)表示以第\(i\)位数字结尾的上升子序列最长的长度是多少。一共有\(n\)个阶段,每次决策选择在\(i\)之前的比\(a_i\)小的数字来更新\(f_i\),状态转移方程就是:\(f_i=max(f_j+1)(0\leqslant j<i,a_j<a_i)\)。\(f\)初始均为\(0\),最后求出整个数组的最大值即为答案。

时间复杂度:\(O(n^2)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std; const int maxn=1e3+5; int n,ans;
int a[maxn],f[maxn]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} int main() {
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++) {
for(int j=0;j<i;j++)
if(a[j]<a[i])
f[i]=max(f[i],f[j]+1);
ans=max(ans,f[i]);
}
printf("%d\n",ans);
return 0;
}

由于\(f_i\)只会由\(f_j+1\)更新得到(\(j\)是满足\(x<i\)且\(a_x<a_i\)的\(f_x\)最大的\(x\)),那么我们完全没有必要枚举没有用的位置,那样对于时间的浪费就太大。所以我们可以对于这个方程进行改进。

设\(f_i\)为以数字\(i\)结尾的最长上升子序列的长度。那么\(f_i=max(f_j+1)(0\leqslant j <i)\),因为我们的阶段还没有进行到\(i\)后面去,所以\(f_j\)表示的必然是\(i\)前面的某一个数字\(j\)结尾的上升子序列长度。这样子我们就可以用树状数组来维护\(f\)数组,每次查询前缀最大值\(+1\)来更新当前的\(f_{a_i}\),然后再在树状数组上改动相应的位置即可。如果序列的值域一开始不在\([1,n]\),那么我们离散化即可。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
#define low(i) ((i)&(-(i))) const int maxn=1e5+5; int n,cnt;
int tmp[maxn],a[maxn]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} struct tree_array {
int c[maxn]; void change(int pos,int v) {
for(int i=pos;i<=cnt;i+=low(i))
c[i]=max(c[i],v);
} int query(int pos) {
int res=0;
for(int i=pos;i;i-=low(i))
res=max(res,c[i]);
return res;
}
}T; int main() {
n=read();
for(int i=1;i<=n;i++)
tmp[i]=a[i]=read();
sort(tmp+1,tmp+n+1);
cnt=unique(tmp+1,tmp+n+1)-tmp-1;
for(int i=1;i<=n;i++) {
a[i]=lower_bound(tmp+1,tmp+cnt+1,a[i])-tmp;
int f=T.query(a[i]-1)+1;
T.change(a[i],f);
}
printf("%d\n",T.query(n));
return 0;
}

洛谷【AT2827】LIS的更多相关文章

  1. 【模板】最长上升子序列(LIS)及其优化 & 洛谷 AT2827 LIS

    最长上升子序列 传送门 题意 对于给定的一个n个数的序列,找到它的一个最长的子序列,并且保证这个子序列是由低到高排序的. 例如,1 6 2 5 4 6 8的最长上升子序列为1 2 4 6 8. 基本思 ...

  2. 洛谷 AT2827 LIS

    题目传送门 解题思路: 用f[i]表示长度为i的最长上升子序列的最小的末尾. AC代码: #include<iostream> #include<cstdio> #includ ...

  3. P1091 合唱队形题解(洛谷,动态规划LIS,单调队列)

    先上题目 P1091 合唱队形(点击打开题目) 题目解读: 1.由T1​<...<Ti​和Ti​>Ti+1​>…>TK​可以看出这题涉及最长上升子序列和最长下降子序列 2 ...

  4. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  5. 【模板】LIS模板 洛谷P1091 [NOIP2004提高组]合唱队形 [2017年4月计划 动态规划11]

    以题写模板. 写了两个:n^2版本与nlogn版本 P1091 合唱队形 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队 ...

  6. 洛谷1439 排列LCS问题

    洛谷1439 排列LCS问题 本题地址:http://www.luogu.org/problem/show?pid=1439 题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输 ...

  7. 洛谷P3928 Sequence2(dp,线段树)

    题目链接: 洛谷 题目大意在描述底下有.此处不赘述. 明显是个类似于LIS的dp. 令 $dp[i][j]$ 表示: $j=1$ 时表示已经处理了 $i$ 个数,上一个选的数来自序列 $A[0]$ 的 ...

  8. DP【洛谷P1704】 寻找最优美做题曲线

    [洛谷P1704] 寻找最优美做题曲线 题目背景 nodgd是一个喜欢写程序的同学,前不久(好像还是有点久了)洛谷OJ横空出世,nodgd同学当然第一时间来到洛谷OJ刷题.于是发生了一系列有趣的事情, ...

  9. 洛谷1439:最长公共子序列(nlogn做法)

    洛谷1439:最长公共子序列(nlogn做法) 题目描述: 给定两个序列求最长公共子序列. 这两个序列一定是\(1\)~\(n\)的全排列. 数据范围: \(1\leq n\leq 10^5\) 思路 ...

随机推荐

  1. 【Head First Servlets and JSP】笔记11:cookie

    容器如何知道客户是谁?(这并不是HTTP能实现的!IP地址不能唯一的标识用户,另外,非必要不采用HTTPS 继续mark孤傲苍狼的博客,百科全书 cookie——Header——字典——键值对—— 延 ...

  2. 在安装mysqli的时候,出现error: ext/mysqlnd/mysql_float_to_double.h: No such file or directory

    /application/php5.:: warning: /ext/mysqli/mysqli_api.c::: error: ext/mysqlnd/mysql_float_to_double.h ...

  3. SQL单行函数和多行函数

    单行函数和多行函数示意图: 单行函数分为五种类型:字符函数.数值函数.日期函数.转换函数.通用函数 单行函数: --大小写控制函数 select lower('Hello World') 转小写, u ...

  4. 七、golang中接口、反射

    一.接口定义 1.定义 interface类型可以定义一组方法,但是这些不需要实现,并且interface不能包含任何变量 package main import ( "fmt" ...

  5. git上面创建个人简历-链接

    github创建个人在线简历: https://segmentfault.com/a/1190000006820290

  6. Go Interface概念

    简单地说 Interface是一组Method的组合,可以通过Interface来定义对象的一组行为.如果某个对象实现了某个接口的所有方法,就表示它实现了该借口,无需显式地在该类型上添加接口说明.In ...

  7. 单选框radio 选择问题

    <input type="radio"  name="test"/> <input type="radio"  name= ...

  8. myEclipse 输入时英文自动变成2个字符大小

    比如这样: ——这是输入法的问题,输入法被误设为圆角了. 输入法有区分圆角半角,正常来说我们使用的都是半角. 那么如何切换半圆角? ——比如:百度输入法 首先,将半圆角的快捷键显示出来: ——点击“d ...

  9. getchar与scanf区别

    scanf可以一次按照设定的输入格式输入多个变量数据.如int d,float f,char str[20],scanf("%d%f%s",d,f,str); getchar()只 ...

  10. git 里面遇到的问题

    第一步:建立git仓库(本地) cd到你的本地项目根目录下,执行git命令 git init 第二步:将项目的所有文件添加到仓库中 git add . 如果想添加某个特定的文件,只需把.换成特定的文件 ...