题意:给定一个长度为 N<=105 的序列 求删去连续长度为 0<=L<=N 的序列后的 LIS
思路:
假设你已经会
O(nlogn)的LIS
,
删去i
前面连续一段长度为
L
即[i−L,i-1]
的 序列, 左边是
i−L−1
, 右边是
i
, 求剩下的
LIS
首先预处理出:
f[i]:=以a[i]结尾的LIS的最大长度
g[i]:=以a[i]开头的LIS的最大长度
我们可以根据
i
, 找到
[0,i−L−1]
之间的一个值
其值小于
a[i]
, 而其
f[i]
值是最大的, 也就是
O(n2)
求LIS的思想
关键是如何快速确定在
[0,i−L−1]
中, 找到这个值
我们利用线段树和离散化, 将
a[i]
映射到线段树上
假设
i
位置对应的值是
x
,并且其映射到线段树上对应的下标是
y
那么我们只要在线段树上查找
[0,y−1]
之间的最大值
maxv
maxv[i]=max{f[j],j∈[0,i−L+1]∪a[j]<a[i]}
其实就是
dp[i]:=
以
a[i]
结尾, 删去
[i−L,i−1]
长度为
L
的
LIS
的最大长度
dp[i]=maxv[i]+g[i],ans=max{dp[i]}
注意:普通的LIS算法只能求得区间内的LIS但不能保证毕包含头或尾,
这里利用lower_bound函数在nlogn的时间求任意前缀且包含前缀尾的LIS ( 即f[ i ] )。
同样利用该函数求得任意后缀且包含后缀头的LIS ( 即g[ i ] )。
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<stdio.h>
#include<math.h>
#include <string>
#include<string.h>
#include<map>
#include<queue>
#include<set>
#include<utility>
#include<vector>
#include<algorithm>
#include<stdlib.h>
using namespace std;
#define eps 1e-8
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define ll long long int
#define mod 1000003
#define maxn 110000
#define maxm 10001005
int mi(int a,int b){return a<b?a:b;}
int ma(int a,int b){return a>b?a:b;}
int n,t,L,ans;
int a[maxn],aa[maxn];
int f[maxn],g[maxn],h[maxn];
int mx[maxn*4];
void update(int rt,int x,int v,int l,int r){
if(l==r) {
mx[rt]=ma(mx[rt],v);
return;
}
int mid=(l+r)>>1;
if(mid>=x) update(rt*2,x,v,l,mid);
else update(rt*2+1,x,v,mid+1,r);
mx[rt]=ma(mx[rt*2],mx[rt*2+1]);
}
int query(int rt,int lx,int rx,int l,int r){
if(l==lx&&r==rx) return mx[rt];
int mid=(l+r)>>1;
if(rx<=mid) return query(rt*2,lx,rx,l,mid);
else if(lx>mid) return query(rt*2+1,lx,rx,mid+1,r);
else {
int lv=query(rt*2,lx,mid,l,mid);
int rv=query(rt*2+1,mid+1,rx,mid+1,r);
return ma(lv,rv);
}
}
int main()
{
rd(t);
int tt=0;
while(t--){
rd2(n,L);
for(int i=1;i<=n;i++){
rd(a[i]);
aa[i]=a[i];
}
sort(aa+1,aa+1+n);
int nn=unique(aa+1,aa+1+n)-aa-1;
memset(h,0x3f,sizeof h);
for(int i=1;i<=n;i++){//求1~i的包含a[i]的LIS!!
int k=lower_bound(h+1,h+1+n,a[i])-h;
f[i]=k;
h[k]=a[i];
}
memset(h,0x3f,sizeof h);
for(int i=n;i>=1;i--){//求i~n的包含a[i]的LIS!!
int k=lower_bound(h+1,h+1+n,-a[i])-h;
g[i]=k;
h[k]=-a[i];
}
a[0]=f[0]=g[n+1]=0; a[n+1]=0x3f3f3f3f;
memset(mx,0,sizeof mx);
ans=0;
for(int i=L+1;i<=n+1;i++){
int k=lower_bound(aa+1,aa+1+nn,a[i])-aa;
int v=query(1,0,k-1,0,nn);
ans=ma(ans,v+g[i]);
k=lower_bound(aa+1,aa+1+nn,a[i-L])-aa;
if(i<=n) update(1,k,f[i-L],0,nn);
}
printf("Case #%d: %d\n",++tt,ans);
}
return 0;
}