题干:
Given a sequence of numbers A=a1,a2,…,aNA=a1,a2,…,aN, a subsequence b1,b2,…,bkb1,b2,…,bk of AA is referred as increasing if b1<b2<…<bkb1<b2<…<bk. LY has just learned how to find the longest increasing subsequence (LIS).
Now that he has to select LL consecutive numbers and remove them from AA for some mysterious reasons. He can choose arbitrary starting position of the selected interval so that the length of the LIS of the remaining numbers is maximized. Can you help him with this problem?
Input
The first line of input contains a number TT indicating the number of test cases (T≤100T≤100).
For each test case, the first line consists of two numbers NN and LL as described above (1≤N≤100000,0≤L≤N1≤N≤100000,0≤L≤N). The second line consists of NN integers indicating the sequence. The absolute value of the numbers is no greater than 109109.
The sum of N over all test cases will not exceed 500000.
Output
For each test case, output a single line consisting of “Case #X: Y”. XX is the test case number starting from 1. YY is the maximum length of LIS after removing the interval.
Sample Input
2 5 2 1 2 3 4 5 5 3 5 4 3 2 1
Sample Output
Case #1: 3 Case #2: 1
题目大意:
每组样例给出两个整数N和L,然后给你N个数的序列,问删除连续的L个数之后,剩下的数的LIS的长度。
解题报告:
维护两个数组pre[i]和suf[i],分别代表从前往后以i为结尾的LIS和从后往前以i为第一个数的LIS。然后权值线段树维护离散化后的以每个值做开头,一直到结尾的最长LIS长度,然后查询的时候就枚举断点就好了。但是只有后缀的情况在此时会枚举不到,所以要单独枚举一下。但是只有前缀的情况是可以考虑到的不需要特判了。
注意预处理数组的时候需要单独开变量记录长度,因为数组中记录的必须是以当前点为结尾的。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 1e5 + 5;
int n,L,a[MAX],b[MAX],LEN;
int get(int x) {
return lower_bound(b+1,b+LEN+1,x) - b;
}
int suf[MAX],pre[MAX],tmp[MAX];
struct TREE {
int l,r,mx;
} tr[MAX<<2];
void pushup(int cur) {
tr[cur].mx = max(tr[cur*2].mx,tr[cur*2+1].mx);
}
void build(int l,int r,int cur) {
tr[cur].l = l,tr[cur].r = r;tr[cur].mx = 0;
if(l == r) return;
int m = l+r >>1;
build(l,m,cur*2);build(m+1,r,cur*2+1);
}
void update(int tar,int val,int cur) {
if(tr[cur].l == tr[cur].r) {
tr[cur].mx = max(tr[cur].mx,val);return;
}
if(tar <= tr[cur*2].r) update(tar,val,cur*2);
else update(tar,val,cur*2+1);
pushup(cur);
}
int query(int pl,int pr,int cur) {
if(pl > pr) return 0;
if(pl <= tr[cur].l && pr >= tr[cur].r) return tr[cur].mx;
int res = 0;
if(pl <= tr[cur*2].r) res = max(res,query(pl,pr,cur*2));
if(pr >= tr[cur*2+1].l) res = max(res,query(pl,pr,cur*2+1));
return res;
}
int my_lower_bound(int l,int r,int x) {
int ans=r+1,mid;
while(l<=r) {
mid = l+r >>1;
if(tmp[mid] < x) ans = mid,r = mid-1;
else l = mid+1;
}
return ans;
}
int main()
{
int T,iCase=0;
cin>>T;
while(T--) {
scanf("%d%d",&n,&L);
for(int i = 1; i<=n; i++) scanf("%d",a+i),b[i] = a[i];
sort(b+1,b+n+1); LEN = unique(b+1,b+n+1) - b - 1;
int len = 0;
for(int i = 1; i<=n; i++) {
int pos = lower_bound(tmp+1,tmp+len+1,a[i]) - tmp;
pre[i] = pos;
if(pos > len) len = pos;
tmp[pos] = a[i];
} suf[n+1] = 0; len = 0;
for(int i = n; i>=1; i--) {
int pos = my_lower_bound(1,len,a[i]);
suf[i] = pos;
if(pos > len) len = pos;
tmp[pos] = a[i];
}
build(1,n,1);
int ans = 0;
for(int i = L+1; i<=n; i++) ans = max(ans,suf[i]);
for(int i = n-L; i>=1; i--) {//枚举被删除的数字的起点
ans = max(ans,pre[i]+query(get(a[i])+1,n,1));
update(get(a[i+L]),suf[i+L],1);
}
printf("Case #%d: %d\n",++iCase,ans);
}
return 0 ;
}