LIS(O (n*logn))
lower_bound & upper_bound用法
假设我们查找x,那么:
lower_bound会找出序列中第一个大于等于x的数
upper_bound会找出序列中第一个大于x的数
但是!!只能对升序的序列找,如果是降序的,加一个greater<int>()
假设我们查找x,那么:
lower_bound会找出序列中第一个大于等于x的数
upper_bound会找出序列中第一个大于x的数
但是!!只能对升序的序列找,如果是降序的,加一个greater<int>()
n*logn 求LIS的算法
定义x[i]表示长度为 i的LIS结尾的数(定义很重要!!)
如果求的是最长上升子序列的话,同样的i,我们希望x[i]越小越好,因为这样后面的数能接上来的可能性越大
所以每当进来一个数a[i],如果可以接上,就将长度增加
否则就找到第一个大于等于它的数,将那个数更新成它
定义x[i]表示长度为 i的LIS结尾的数(定义很重要!!)
如果求的是最长上升子序列的话,同样的i,我们希望x[i]越小越好,因为这样后面的数能接上来的可能性越大
所以每当进来一个数a[i],如果可以接上,就将长度增加
否则就找到第一个大于等于它的数,将那个数更新成它
为什么是大于等于呢?
如果有一个数是和它相等的,那么优先找到的就是相等的数,即相当于没更新
如果改成大于,把大于它的更新成了它,就说明有两个长度结尾的数是一样的
由于求的是最长上升,不能相同,就矛盾了
总结:
严格上升:用lower_bound 可以相等:用upper_bound 降序序列:加greater<int>()
#include<bits/stdc++.h> using namespace std; #define inf 2100000000 #define N 100005 int n=0,a[N],x1[N],x2[N],l1,l2; bool read() { char ch=getchar(); if(ch==EOF) return false; int fl=1,x=0; while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); } while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); a[++n]=x; return true; } int main() { while(read()); x1[++l1]=a[1]; x2[++l2]=a[1]; for(int i=2;i<=n;i++){ if(a[i]<=x1[l1]) x1[++l1]=a[i]; else{ int pos=upper_bound(x1+1,x1+1+l1,a[i],greater<int>())-x1; x1[pos]=a[i]; } if(a[i]>x2[l2]) x2[++l2]=a[i]; else{ int pos=lower_bound(x2+1,x2+1+l2,a[i])-x2; x2[pos]=a[i]; } } printf("%d\n%d\n",l1,l2); } //389 207 155 300 299 170 158 65