题意
给出一个长度为n的序列,有一些位置可以放任意的数,问最长上升序列的长度。
n<=100000
分析
dalao们的做法都好劲啊,就我的做法最暴力。。。
考虑用二分求lis做法,用一个f[i]维护长度为i的最长上升序列的结尾的最小值。若当前要处理的位置是有数字的则直接处理,否则设当前的最长上升序列长度为maxlen,则f[i]=f[i-1]+1 (1<=i<=maxlen+1),那么我们可以考虑用一个变量add表示f数组中的每一个数都被加上了add,然后把整个序列向后移一位即可。我的处理方法是维护一个pos表示f序列的结尾下标,那么开头下标就是pos-maxlen+1了。
一次AC吼爽啊!!!
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 200005
#define inf 0x7fffffff
using namespace std;
int n,maxlen,add,pos,f[N],a[N];
int ef(int x)
{
int l=pos-maxlen+1,r=pos;
while (l<=r)
{
int mid=(l+r)/2;
if (f[mid]+add<x) l=mid+1;
else r=mid-1;
}
return l-1;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
char ch[2];
scanf("%s",ch);
if (ch[0]=='N') a[i]=inf;
else scanf("%d",&a[i]);
}
pos=n;
maxlen=add=0;
for (int i=1;i<=n;i++)
if (a[i]==inf)
{
add++;
maxlen++;
f[pos-maxlen+1]=-inf;
}else
{
int x=ef(a[i]),len=x-pos+maxlen+1;
if (len>maxlen)
{
maxlen=len;
pos++;
f[pos]=a[i]-add;
}
else f[x+1]=min(f[x+1],a[i]-add);
}
printf("%d",maxlen);
return 0;
}