题意:删去连续的长度为L的序列,求最长上升子序列。严格上升。
dp[i][0]代表选择i点在[1,i]中找最长上升子序列。
dp[i][1]代表删去了长度为L的连续序列之后选择i点的在[1,i]中的最长上升子序列。
离散化加线段树维护求区间最大值。
坑点:忘了我最后找的状态是选择了第n个点的dp[n][1],可是还有可能是因为dp[n+1][1],即最后删除n-L+1到n这一段连续序列之后的最长上升子序列。真坑,wc。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=101000;
struct node{
int l,r,max0,max1,max2;
}a[MAX_N*4];
void update(int k){
a[k].max0=max(a[k<<1].max0,a[k<<1|1].max0);
a[k].max1=max(a[k<<1].max1,a[k<<1|1].max1);
a[k].max2=max(a[k<<1].max2,a[k<<1|1].max2);
}
void build(int k,int l,int r){
a[k].l=l;a[k].r=r;
if(l==r){
a[k].max0=0;
a[k].max1=0;
a[k].max2=0;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
update(k);
}
void change0(int k,int x,int y){
if(a[k].l==a[k].r){
a[k].max0=max(y,a[k].max0);
return;
}
int mid=(a[k].l+a[k].r)/2;
if(x<=mid)
change0(k<<1,x,y);
else
change0(k<<1|1,x,y);
update(k);
}
void change1(int k,int x,int y){
if(a[k].l==a[k].r){
a[k].max1=max(y,a[k].max1);
return;
}
int mid=(a[k].l+a[k].r)/2;
if(x<=mid)
change1(k<<1,x,y);
else
change1(k<<1|1,x,y);
update(k);
}
void change2(int k,int x,int y){
if(a[k].l==a[k].r){
a[k].max2=max(y,a[k].max2);
return;
}
int mid=(a[k].l+a[k].r)/2;
if(x<=mid)
change1(k<<1,x,y);
else
change1(k<<1|1,x,y);
update(k);
}
int query0(int k,int l,int r){
if(a[k].l>=l&&a[k].r<=r)
return a[k].max0;
int mid=(a[k].l+a[k].r)>>1;
int x=0;
if(r>mid)
x=max(x,query0(k<<1|1,l,r));
if(l<=mid)
x=max(x,query0(k<<1,l,r));
return x;
}
int query1(int k,int l,int r){
if(a[k].l>=l&&a[k].r<=r)
return a[k].max1;
int mid=(a[k].l+a[k].r)>>1;
int x=0;
if(r>mid)
x=max(x,query1(k<<1|1,l,r));
if(l<=mid)
x=max(x,query1(k<<1,l,r));
return x;
}
int query2(int k,int l,int r){
if(a[k].l>=l&&a[k].r<=r)
return a[k].max2;
int mid=(a[k].l+a[k].r)>>1;
int x=0;
if(r>mid)
x=max(x,query2(k<<1|1,l,r));
if(l<=mid)
x=max(x,query2(k<<1,l,r));
return x;
}
int dp[101000][2];
int aa[101000],sub_a[101000],b[101000];
int main(void){
int T,n,L,i;
cin>>T;
int t=T;
while(T--){
scanf("%d%d",&n,&L);
//dp[0][0]=0;dp[0][1]=0;
for(i=1;i<=n;i++){
dp[i][0]=0;
dp[i][1]=0;
scanf("%d",&aa[i]);
sub_a[i-1]=aa[i];
}
sort(sub_a,sub_a+n);
int nn=unique(sub_a,sub_a+n)-sub_a;
for(i=1;i<=n;i++){
b[i]=lower_bound(sub_a,sub_a+nn,aa[i])-sub_a+1;
//cout<<b[i]<<"\n";
}
b[0]=0;
build(1,0,n);
int ans=0;
for(i=1;i<=n;i++){
dp[i][0]=query0(1,0,b[i]-1)+1;
//ans=max(ans,dp[i][0]);
change0(1,b[i],dp[i][0]);
if(i>L){
change1(1,b[i-L-1],dp[i-L-1][0]);
//dp[i][1]=dp[i-L-1][0]+1;
dp[i][1]=query1(1,0,b[i]-1)+1;
dp[i][1]=max(dp[i][1],query2(1,0,b[i]-1)+1);
change2(1,b[i],dp[i][1]);
ans=max(ans,dp[i][1]);
}
}
ans=max(ans,dp[n-L][0]);
printf("Case #%d: %d\n",t-T,ans);
}
return 0;
}