合理运用单调性降低复杂度

平常用的都是O(n^2)的dp求LIS(最长不下降子序列)
这里介绍O(nlogn)的算法

分析

  • 对于可能出现的x<y<iA[y]<A[x]<A[i],则x相对于y更有潜力

    • 因为接下来可能出现A[y]<A[z]<A[x]x<z<i
  • 我们以f[i]表示前i个数中的LIS最长长度;
    • 当出现f[x]==f[y]时,就应该选择x而不会是y
  • 我们可以得到以下思想
    • 首先根据f[]值分类,记录满足f[t]=k的最小的值a[t],记d[k]=min{a[t]},f[t]=k.
    • 1.发现d[k]在计算过程中单调不上升
    • 2.d[1]<d[2]<...<d[k] (反证) 1 2 3 8 4 7
  • 由此得到解法
    • 设当前最长递增子序列为len,考虑元素a[i];
    • d[len]<a[i],则len++,并将d[len]=a[i];否则,在d[0-len]中二分查找,找到第一个比它小的元素d[k],并令d[k+1]=a[i]

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 41000;
int a[N]; //a[i] 原始数据
int d[N]; //d[i] 长度为i的递增子序列的最小值
int BinSearch(int key, int* d, int low, int high) {
while(low<=high) {
int mid = (low+high)>>1;
if(key>d[mid] && key<=d[mid+1])
return mid;
else if(key>d[mid]) low=mid+1;
else high=mid-1;
}
return 0;
}
int LIS(int* a, int n, int* d) {
int i,j;
d[1]=a[1];
int len=1; //递增子序列长度
for(i=2; i<=n; i++) {
if(d[len]<a[i]) j=++len;
else j=BinSearch(a[i],d,1,len)+1;
d[j]=a[i];
}
return len;
}
int main() {
int t;
int p;
scanf("%d",&t);
while(t--)
{
scanf("%d",&p);
for(int i = 1; i <= p; i++) scanf("%d",&a[i]);
printf("%d\n",LIS(a,p,d));
}
return 0;
}

【模板】O(nlongn)求LIS的更多相关文章

  1. nlogn求LIS(树状数组)

    之前一直是用二分 但是因为比较难理解,写的时候也容易忘记怎么写. 今天比赛讲评的时候讲了一种用树状数组求LIS的方法 (1)好理解,自然也好写(但代码量比二分的大) (2)扩展性强.这个解法顺带求出以 ...

  2. Codeforces 486E LIS of Sequence --树状数组求LIS

    题意: 一个序列可能有多个最长子序列,现在问每个元素是以下三个种类的哪一类: 1.不属于任何一个最长子序列 2.属于其中某些但不是全部最长子序列 3.属于全部最长子序列 解法: 我们先求出dp1[i] ...

  3. hdu5256 二分求LIS+思维

    解题的思路很巧,为了让每个数之间都留出对应的上升空间,使a[i]=a[i]-i,然后再求LIS 另外二分求LIS是比较快的 #include<bits/stdc++.h> #define ...

  4. hdu 1025LIS思路同1257 二分求LIS

    题目: Constructing Roads In JGShining's Kingdom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit ...

  5. HDU 5773 The All-purpose Zero(O(nlgn)求LIS)

    http://acm.hdu.edu.cn/showproblem.php?pid=5773 题意: 求LIS,其中的0可以看做任何数. 思路: 因为0可以看做任何数,所以我们可以先不管0,先求一遍L ...

  6. poj1631——树状数组求LIS

    题目:http://poj.org/problem?id=1631 求LIS即可,我使用了树状数组. 代码如下: #include<iostream> #include<cstdio ...

  7. HDU1087(树状数组求LIS)

    题是水题,学习一下用树状数组求LIS. 先离散化一下,注意去重:然后就把a[i]作为下标,dp[i]作为值,max作为维护的运算插进树状数组即可. 如果是上升子序列,询问(a[i] - 1):如果是不 ...

  8. UVA 10635 Prince and Princess—— 求LCS(最长公共子序列)转换成 求LIS(最长递增子序列)

    题目大意:有n*n个方格,王子有一条走法,依次经过m个格子,公主有一种走法,依次经过n个格子(不会重复走),问他们删去一些步数后,重叠步数的最大值. 显然是一个LCS,我一看到就高高兴兴的打了个板子上 ...

  9. 树状数组求LIS模板

    如果数组元素较大,需要离散化. #include <iostream> #include <cstdio> #include <cstring> #include ...

随机推荐

  1. java+selenium使用JS、键盘滑动滚动条

    本篇文章介绍如何使用JS和键盘对象对页面进行滑动滚动条-------------主要针对java做自动化测试的同学 一:使用键盘对象操作滚动条 //导包 import org.openqa.selen ...

  2. 跟我一起学Go系列:gRPC 入门必备

    RPC 的定义这里就不再说,看文章的同学都是成熟的开发.gRPC 是 Google 开源的高性能跨语言的 RPC 方案,该框架的作者 Louis Ryan 阐述了设计这款框架的动机,有兴趣的同学可以看 ...

  3. Js的变量、作用域与内存

    变量.作用域与内存 1 .原始值与引用值 Undefined.Null.Boolean.Number. String和Symbol.保存原始值的变量是按值(by value)访问的 引用值是保存在内存 ...

  4. opencv——机器视觉检测和计数

    引言 在机器视觉中,有时需要对产品进行检测和计数.其难点无非是对于产品的图像分割. 由于之前网购的维生素片,有时候忘了今天有没有吃过,就想对瓶子里的药片计数...在学习opencv以后,希望实现对于维 ...

  5. OO随笔之追求完美的第三单元——初试JML

    前言 这一章的JML比较简单,那么大家的关注点自然地移到了性能优化上.于是大家一股脑地去利用各种数据结构去做时间上的优化(当然很多人最后还是倒在了正确性上),故称追求完美的一单元.当然这也是得益于JM ...

  6. g77介绍 g77 是 Fortran77 的编译器。它对 Fortran 77 标准提供完备的支持,并支持 Fortran 90 和 95 的部分特性。 由于 Fortran 77 标准在数值计算中的影响力,g77 可能是应用最广的Fortran编译器。 在 GCC 4.0 之前,g77 是 GCC 的一部分,但现在,g77 已经停止开发。

    GFORTRAN 维基百科,自由的百科全书     跳到导航 跳到搜索 此条目需要扩充. (2018年11月2日)请协助改善这篇条目,更进一步的信息可能会在讨论页或扩充请求中找到.请在扩充条目后将此模 ...

  7. 攻防世界(十)NewsCenter

    攻防世界系列 :NewsCenter 方法一 1.打开题,看到搜索框首先想到的是sql注入 2.检查注入点 -1' union select 1,2,3# 存在注入漏洞 3.查库 附:Sql注入常见语 ...

  8. k8s滚动更新(8)

    一.k8s版本更新 滚动更新是一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新.滚动更新的最大的好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性. 实践:部署 ...

  9. 03丨认识文档数据库MongoDB

  10. SQLZOO

    一.SELECT basics/zh 以顯示德國 Germany 的人口. select population from world where name = 'Germany'; 查詢面積為 5,0 ...