为了便于思考,采用从前往后求最长不下降子序列,
stack
改了好多次,刚开始是个结构,有两个域,分别是a
和length
表示比a大的数,最长不下降子序列长度至少为length
,
(Ps:如果从前往后推的话,更新f[i]
的条件是a[j]<=a[i](0<j<i)
且f[j]>=f[i]
,
f[i]在1~i-1上比比它小的数的最长不下降子序列的最大值大1,有点拗口,但就是
f[i]=max{f[j]}+1,(a[j]<=a[i] and 1<j<i)
这样就可以通过记录比a[i]小的数来二分找出f[j])
但之后发现stack[i].length==i;
瞬间凌乱了…
立刻切掉一个域
stack[j]
就表示在已经找过的数中长度为j的最长不下降子序列的末尾元素的最小值,
还是有点拗口,但
f[i]=max{j}+1,(stack[j]<=i)
就可以通过二分来找出stack[j]<=i
的j的最大值
#include<cstdio>
const int maxn=100000;
int f[maxn],stack[maxn],max;
int find(int k)//二分查找
{
int l=0,r=max,m;
do{
m=(l+r)/2;
if(stack[m]>k)r=m-1;else l=m;
}while(l<r-1);//这个条件和上面的语句改了很多次,发现只能另判断是l处取到还是j处取到,希望留言改进
if(r==l+1&&stack[r]<=k)return r;else return l;
}
void join(int a,int length)//见最上面stack[i].length==i
{
if(stack[length]&&stack[length]<=a)return;//比较懒,省了初始化stack,直接在处理时判断:stack若有值并且之前的状态比现在优就退出
stack[length]=a;
}
int main()
{
int a,n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&a);
if((f[i]=find(a)+1)>max)max=f[i];
/*给p党看,相当于
* f[i]=find(a)+1;
* if(f[i]>max)max=f[i];*/
join(a,f[i]);
}
printf("%d",max);
return 0;
}