LIS 的 nlogn算法

HOJ 1288 Bridging Signals

http://acm.hit.edu.cn/hoj/problem/view?id=1288

以前只知道也只听说过 O(n*n) 的LIS 算法

但是过不了这个题,结果才知道还有一种O(nlogn)的算法。

具体思路就是用一个数组ans[len] 记录下对应 len 长度的 LIS 的最末尾元素的最小值。

这样的到的ans[len] 是一个有序的数组,所以用二分查找就能优化时间复杂度。

设 a[n] = 3,5,1,2,4;

===========================

1: ans[1] = 3;len = 1;

2: 因为a[2] = 5 > ans[1] = 3, 所以跟新 ans[2] = 5,   ans = 3,5;

3: 因为a[3] = 1 < ans[1] = 3, 所以跟新 ans[1] = 1,   ans = 1,5;

4: 因为a[4] = 2 < ans[2] = 5, 所以跟新 ans[2] = 2,   ans = 1,2;

...

...

...

===========================

每次查找用二分搜索得到( 注意要查找不大于a[i] 的最大的ans[pos] )

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 40000

using namespace std;

int a[maxn];
int ans[maxn];
int len;

int bi_search(int i){
    int left,right,mid;
    left = 0,right = len;
    while(left < right){
        mid = (left + right) / 2;
        if(ans[mid] >= a[i]) right = mid;
        else left = mid + 1;
//        printf("%d %d %d\n",left,right,mid);
    }
    return left;
}
int main(){
    int t;
    int n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
            scanf("%d",&a[i]);
        ans[1] = a[1];
        len = 1;
        for(int i = 2; i <= n; i++){
            if(a[i] > ans[len]){
                ans[++len] = a[i];
            }
            else{
                int pos = bi_search(i);
//                int pos = lower_bound(ans,ans+len,a[i])-ans;
//                printf("|%d|\n",pos);
                ans[pos] = a[i];
            }
        }
        printf("%d\n",len);
    }

    return 0;
}

时间: 2024-10-07 13:16:02

LIS 的 nlogn算法的相关文章

NOIp模拟1 Incr(LIS的nlogn算法)

[分析] 这题就是拿总长度减去LIS啦,很明显. 问题是数据范围,这里用n^2就会超时,所以我们选用LIS的nlogn算法,如下. [代码] 1 #include <bits/stdc++.h> 2 #define inf 0x7fffffff 3 using namespace std; 4 5 int n, a[100005], k, f[100005], ans; 6 int g[100005];//记录当前的最优子序列 7 8 int main() { 9 cin >> n

Laoj P1659 noip模拟 - 道路规划(LCS的nlogn算法)

试题描述 吉丽王国有n个城市,每个城市有两个"附属城市",其中北部有n个城市,每个城市的编号都是1~n中的一个,且互不相同,南部的n个城市也是如此.很遗憾,南北两边的城市之间还没有道路连接,这个南北交通运输带来了很大的麻烦.国王吉丽设计规划了一种方案,决定先建n条道路,即编号相同的两个城市之间连上一条道路.如图所示,这就是建完道路后的样子.如果第i个城市和第j个城市的两条道路相交了,那么我们称这两个城市"平等互惠".吉丽想找出一个城市集合,使得集合中的任意两个城市都

最长上升子序列(LIS)长度的O(nlogn)算法

最长上升子序列(LIS)的典型变形,熟悉的n^2的动归会超时.LIS问题可以优化为nlogn的算法.定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素.注意d中元素是单调递增的,下面要用到这个性质.首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i];否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需

最长递增子序列 O(NlogN)算法

https://www.felix021.com/blog/read.php?entryid=1587&page=3&part=1 感谢作者! 标题:最长递增子序列 O(NlogN)算法 出处:Blog of Felix021 时间:Wed, 13 May 2009 04:15:10 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?1587  内容: 今天回顾WOJ1398,发现了这个当时没有理解透彻的算法. 看了好久

HDU ACM 1025 Constructing Roads In JGShining&amp;#39;s Kingdom-&amp;gt;二分求解LIS+O(NlogN)

#include<iostream> using namespace std; //BFS+优先队列(打印路径) #define N 500005 int c[N]; int dp[N]; //dp[i]保存的是长度为i的最长不降子序列的最小尾元素 int BS(int n,int x) //二分查找下标,当x比全部元素小时下标为1,比全部元素大时下标为n+1. { int low,high,mid; low=1,high=n; while(low<=high) { mid=(low+h

HDU ACM 1025 Constructing Roads In JGShining&#39;s Kingdom-&gt;二分求解LIS+O(NlogN)

#include<iostream> using namespace std; //BFS+优先队列(打印路径) #define N 500005 int c[N]; int dp[N]; //dp[i]保存的是长度为i的最长不降子序列的最小尾元素 int BS(int n,int x) //二分查找下标,当x比所有元素小时下标为1,比所有元素大时下标为n+1. { int low,high,mid; low=1,high=n; while(low<=high) { mid=(low+h

LIS的优化算法O(n log n)

LIS的nlogn的优化:LIS的优化说白了其实是贪心算法,比如说让你求一个最长上升子序列把,一起走一遍. 比如说(4, 2, 3, 1, 2,3,5)这个序列,求他的最长上升子序列,那么来看,如果求最长的上升序列,那么按照贪心,应该最可能的让该序列的元素整体变小,以便可以加入更多的元素.现在开辟一个新的数组,arr[ 10 ], { .......} --> 这个是他的空间 ,现在开始模拟贪心算法求解最长上升子序列,第一个数是4,先加进去,那么为{ 4 }再来看下一个数2,它比4小,所以如果他

最长上升子序列O(nlogn)算法详解

最长上升子序列 时间限制: 10 Sec   内存限制:128 MB 题目描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.我们想知道此时最长上升子序列长度是多少? 输入 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N) 输出 1行,表示最长上升子序列的长度是多少. 样例输入 3 0 0 2 样例输出 2 提示 100%的数据 n&l

hdu 1025 Constructing Roads In JGShining&#39;s Kingdom(最长上升子序列nlogn算法)

学习了最长上升子序列,刚开始学的n^2的方法,然后就超时了,肯定超的,最大值都是500000,平方之后都12位 了,所以又开始学nlogn算法,找到了学长党姐的博客orz,看到了rating是浮云...确实啊,这些不必太关 注,作为一个动力就可以啦.没必要看的太重,重要的事学习知识. 思路: 这道题目可以先对一行排序,然后对另一行求最长上升子序列... n^2算法: 序列a[n],设一个数组d[n]表示到n位的时候最长公共子序列(此序列包括n),所以呢 d[n]=max(d[j]+1,0<j<