n方做法不再介绍。
介绍nlogn的做法
假设有一组数据 389 207 155 300 299 170 158 65,求最长下降子序列
依次扫描
389 207 155
扫描到300的时候 更新207为300
扫描到299的时候 更新155为299
【因为300比207更有下降潜质,299比155更有下降潜质】
此时变为389 300 299
剩下170 158 65 依次进去
最后是389 300 299 170 158 65
这个洛谷题目注意,第一次找最长 非严格下降子序列,第二次找 最长 严格上升子序列
upper_bound(x) 寻找第一个大于x的位置,找不到返回数组的尾部元素位置+1的位置
lower_bound(x)寻找第一个大于等于x的位置,找不到返回数组的尾部元素位置+1的位置
注意,默认都是在升序序列上寻找。
如果在降序序列上寻找,需要自定义排序规则cmp。(和sort一种用法)
在降序序列上,upper_bound是第一个小于x的位置
还有一个注意的地方。寻找最长严格下降子序列和寻找最长非严格下降子序列的区别
比如某时刻可能存在 3 2 1和3 2 2 2 2 1的数组。前者需要lowerbound后者需要upperbound。
可以这么考虑。3 2 1 如果严格下降不允许重复的话,此时再来一个2 如果lowerbound肯定会返回
3后面的这个位置。然后就变成了3 2 1;如果允许重复,此时再来一个2,upperbound返回2后面的这个位置(也就是一这个位置),然后就变成了3 2 2
#include<bits/stdc++.h>
using namespace std;
int a[500007];
int cnt;
vector<int>g;
vector<int>gg;
bool cmp(int a,int b){
return a>b;
}
int main(){
int x;
while(cin>>x){
cnt++;
a[cnt]=x;
}
g.push_back(a[1]);
gg.push_back(a[1]);
//先找一下最长 非严格下降子序列
for(int i=2;i<=cnt;i++){
int cur=upper_bound(g.begin(),g.end(),a[i],cmp)-g.begin();
if(cur>=g.size())g.push_back(a[i]);
else g[cur]=a[i];
}
//再找一下最长 严格上升
for(int i=2;i<=cnt;i++){
int cur=lower_bound(gg.begin(),gg.end(),a[i])-gg.begin();
if(cur>=gg.size())gg.push_back(a[i]);
else gg[cur]=a[i];
}
cout<<gg.size();
return 0;
}