第二遍写这道题,写写新的体会,对于最长子序列问题虽然说可以用dp解决,但是这是n方的做法,同时,存在nlogn的更优的做法(更像是贪心一类的),可以自己想想
个人想法:对于二分的时候
我认为 最长上升子序列用lower_bound 最长不降用upper_bound
最长下降子序列用lower_bound 最长不升用upper_bound
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int f[N]={1};
int len;
int b[N];
int c[N];
int lenn;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int k,cnt=0;
while(cin>>k){
a[++cnt]=k;//一共cnt个
}
c[0]=1e9;
for(int i=1;i<=cnt;++i){
if(a[i]<=c[lenn]){
c[++lenn]=a[i];//构造一个动态数组,如果某一个数字小于尾数,就把他放在最后
}
else{
*upper_bound(c+1,c+1+lenn,a[i],greater<int>())=a[i];
//学习一下书写形式 这里的意思是,找到第一个小于a[i]的数字并且将其换掉
//比如说 我有5 3 2 1 现在要插入一个4 这时候 我就替换成5 4 2 1 如此一来就会更优
//这里之所以可以用upper 正是因为他是最长不升
//可以证明,只有出现接着5 4的序列 才会用到它,要不然并不会影响对后面数字的判断
}
}
cout<<lenn<<endl;
b[0]=-1e9;
for(int i=1;i<=cnt;++i){
if(a[i]>b[len]){
b[++len]=a[i];
}
else{
*lower_bound(b+1,b+1+len,a[i])=a[i];
//如果原来是 1 5 7 8 现在插入一个5 就变成1 5 7 8(这里是上升子序列,所以不能用upper_bound,我认为如果是最长不降是可以使用的)
}
}
cout<<len<<endl;
return 0;
}