zoukankan      html  css  js  c++  java
  • 题解 最长上升子序列 LIS

    最长上升子序列 LIS

    Description

    给出一个 1 ∼ n (n ≤ 10^5) 的排列 P
    求其最长上升子序列长度

    Input

    第一行一个正整数n,表示序列中整数个数;
    第二行是空格隔开的n个整数组成的序列。

    Output

    最长上升子序列的长度

    Sample Input

    7
    1 7 3 5 9 4 8

    Sample Output

    4

    解析

    这题(O)((n^2))很容易就能想到,

    然而,(1e5)却会炸掉....

    所以,考虑二分.

    我们维护一个类似于栈的数组(q)(其实是序列但为了方便懒得打字后面就称作栈吧)

    (q[i])表示长度为(i)的序列的最后一个元素,

    那么,从(1)~(n)枚举,每次在(q)中寻找第一个大于等于(a[i])(即权值)的元素,

    再用(a[i])去更新它,并且它的下标就是以(a[i])结尾的最长上升子序列.

    而原因也很简单,对于(i)后面的元素(k)以及(i)更新掉的元素(j),

    首先,根据算法,我们知道(a[i])<=(a[j]),且以(a[i])结尾的上升子序列长度等于以(a[j])结尾的上升子序列长度.

    那么,对于(k),它接到(i)后面和接到(j)后面的效果(即长度)是一样的,

    但是,如果(a[i])<(a[k])<(a[j]),那么(k)能接到(i)后面,却不能接到(j)后面,

    所以,用(i)更新掉(j)一定是更优的,

    并且,(j)的长度也是对于(i)来说最优的,

    因为后面的接不上了.

    于是最后,再从(1)~(n)扫一遍,取最大值就行了.

    口胡证明自己理解下哈

    上代码吧:

    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    
    int n,a[100001],ans=0;
    int f[100001],c[100001];
    
    int main(){
    	n=read();
    	memset(c,0x3f,sizeof(c));
    	for(int i=1;i<=n;i++) a[i]=read();
    	for(int i=1;i<=n;i++){
    		int k=lower_bound(c+1,c+n+1,a[i])-c;
    		f[i]=k;c[k]=a[i];
    	}
    	for(int i=1;i<=n;i++) ans=max(ans,f[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    CodeSmith功能和技巧收集
    简繁转换js兼容各种浏览器
    40 个轻量级 JavaScript 库
    AJAX处理Session
    对项目管理的几点认识(转)
    extjs
    数据采集需要的方法
    JavaScript 浮动定位提示效果
    一个类别表设计
    ExtJS 源码剖析 —— Ext类
  • 原文地址:https://www.cnblogs.com/zsq259/p/10605657.html
Copyright © 2011-2022 走看看