Give
you a numeric sequence. If you can demolish arbitrary amount of
numbers, what is the length of the longest increasing sequence, which is
made up of consecutive numbers? It sounds like
Longest Increasing Subsequence at first sight. So, there is another
limitation: the numbers you deleted must be consecutive.
There are several test cases.
For each test case, the first line of input contains the length of
sequence N(1≤N≤10^4). The second line contains the elements of
sequence——N positive integers not larger than 10^4.
For each the case,
output one integer per line, denoting the length of the longest
increasing sequence of consecutive numbers, which is achievable by
demolishing some(may be zero) consecutive numbers.
/**分析:dp[i][0]代表未删除时以i结尾最长连续上升子序列长度,
dp[i][1]代表删除时以i结尾最长连续上升子序列长度
不删除时很好处理,递推过去就好了,所以可以预处理 dp[i][0]
dp[i][1]可以从dp[i][0]转移过来
1.dp[i][1] = dp[i-1][1]+1 (a[i]>a[i-1])
2.dp[i][1] = dp[j][0]+1 (a[i]>a[j]&&i>j)
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define N 10005
int dp[N][2],a[N],b[N];
int tree[N<<2],MAX;
void pushup(int idx)
{
tree[idx] = max(tree[idx<<1],tree[idx<<1|1]);
}
void build(int l,int r,int idx)
{
if(l==r)
{
tree[idx] = 0;
return;
}
int mid = (l+r)>>1;
build(l,mid,idx<<1);
build(mid+1,r,idx<<1|1);
pushup(idx);
}
void update(int pos,int v,int l,int r,int idx)
{
if(l==r)
{
tree[idx] = max(tree[idx],v);
return;
}
int mid = (l+r)>>1;
if(pos<=mid) update(pos,v,l,mid,idx<<1);
else update(pos,v,mid+1,r,idx<<1|1);
pushup(idx);
}
void query(int l,int r,int L,int R,int idx)
{
if(l>=L&&R>=r)
{
MAX = max(MAX,tree[idx]);
return;
}
int mid = (l+r)>>1;
if(mid>=L) query(l,mid,L,R,idx<<1);
if(mid<R) query(mid+1,r,L,R,idx<<1|1);
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b+1,b+1+n);
int cnt = unique(b+1,b+1+n)-b;
for(int i=1; i<=n; i++) a[i] = lower_bound(b+1,b+cnt,a[i]) - b;
for(int i=1; i<=n; i++)
{
dp[i][0] = 1;
if (i > 1 && a[i]>a[i - 1])
dp[i][0] = dp[i - 1][0] + 1;
}
build(1,n,1);
int ans = -1;
for(int i=1; i<=n; i++)
{
dp[i][1] = 1;
if(i>1&&a[i]>1)
{
if(a[i]>a[i-1]) dp[i][1] = dp[i-1][1]+1;
MAX = -1;
query(1,n,1,a[i]-1,1); /**找到最大的 dp[j][0] 满足 a[j]<a[i] && j<i,有必要解释一下这里
为什么是更新1~a[i]-1呢?因为我们找的是按照大小排名来的数,而不是,比如说 1 3 5 6 4
假设我找的是 a[5] ,所以我应该忽略中间的 5 6 ,直接找 1 3 .而我们的枚举顺序也保证了 j<i 这个条件.
个人觉得很巧妙.
*/
dp[i][1] = max(dp[i][1],MAX+1);
}
update(a[i],dp[i][0],1,n,1);/**
更新过程同样巧妙,也是更新的按照大小排名来的顺序,不要与下标弄混了
*/
ans = max(ans,max(dp[i][1],dp[i][0]));
}
printf("%d\n",ans);
}
return 0;
}