版权声明:随意转载哦......但还是请注明出处吧: 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;
}