2018.10.04 上升序列(线性dp)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82940531

描述

给一个长度10^5的非负序列,序列中的0可以任意换成任何数字(包括负数),问最长严格上升子序列长度。

输入

第一行有一个数n代表序列长度
第二行有n个数字ai代表序列每个值是多少。

输出

一行一个数字代表答案

样例输入

7
2 0 2 1 2 0 5

样例输出

5

提示

30% n<=5000
100% n<=1e5 ai<=1e6


线性dp好题。
我们对于每个非零数先消除前面所有零的贡献。
最后把前导零都加回去就是答案了。
具体来说就是每个非零数减去前面0的数量,求出lis再加上所有0的数量就是答案。
然而如果全是0会gg掉,因此我们在首尾分别插入极小值和极大值作为开头结尾求lis,最后得出的答案减去2就行了。
代码:

#include<bits/stdc++.h>
#define N 100005
using namespace std;
inline int read(){
	int ans=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans*w;
}
int n,d[N],a[N],len=1,cnt=0,tot=0;
int main(){
	n=read();
	a[++tot]=-0x3f3f3f3f;
	for(int i=1;i<=n;++i){
		int tmp=read();
		if(tmp)a[++tot]=tmp-cnt;
		else ++cnt;
	}
	a[++tot]=0x3f3f3f3f,d[1]=a[1];
	for(int i=2;i<=tot;++i){
		int l=1,r=len,ans=0;
		if(d[len]<a[i])d[++len]=a[i];
		else{
			while(l<=r){
				int mid=l+r>>1;
				if(d[mid]<a[i])l=mid+1;
				else r=mid-1;
			}
			d[l]=a[i];
		}
	}
	printf("%d",len+cnt-2);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82940531