思路:通过q[i]记录长度为I的单调上升子序列的结尾数,通过二分找出距离a[i[]值最接近的小于a[i]的数,将a[i]加到这个序列后面,记录过程中所有单调序列的长度,找出最大值输出
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];//储存序列
int q[N];//q[i]储存序列长度为i的最小结尾数,q[]是单调递增的
int n;
int main()
{
cin>>n;
for(int i = 0; i < n; i ++ ) cin>>a[i];
q[0] = 0;//初始化边界
int len = 0;//len记录最长的单调上升子序列的长度
for(int i = 0; i < n; i ++ ){
int l = 0, r = len;//二分的两个边界
while(l < r){//利用二分找到距离a[i]最近的小于a[i]的单调上升序列的结尾数,将a[i]补充到这个序列的末尾
int mid = r + l + 1 >> 1;//l = mid 写法,mid需要上取整,防止mid = 0
if(q[mid] < a[i]) l = mid;//如果q[]此时的中值小于a[i]就让左边界右移减小范围
else r = mid - 1;//否则右边界左移减小范围
}
q[r + 1] = a[i];//找到合适的单调上升序列的结尾数后就将a[i]加到其末尾,序列的长度+1
len = max(len, r + 1); //遍历找出最长单调上升子序列的长度
}
cout<<len<<endl;
return 0;
}