题目链接:https://vjudge.net/problem/UVA-1471
题目大意:给你一个长度为n的序列,你的任务是删除一个连续子序列,使得剩下的序列中有一个长度最大的连续递增子序列。
题目分析:很容易想到一种做法,用fail[j]存储以j结尾的最长上升子序列,用pre[i]存储以i开头的最长上升子序列,那么ans=fail[j]+pre[i](前提是fail[j]<pre[i])
有一个贪心的点,当我们fail[j]和fail[i]同时为x时我肯定要选择a[i]较小的那一个存在min[]数组里,这样就降低了二分时的复杂度
学到的东西:小细节的思考,思维真的很重要啊,过两天之后忘了怎么办!!!lower_bound()的用法,系统自带的二分查找,返回大于val的第一个值的位置。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=200100;
const int inf=1<<30;
int fail[maxn];//以i为结尾的子序列的长度
int pre[maxn];//以i为开头的子序列的长度
int Min[maxn];
int a[maxn];
int main()
{
int i,n,T;
scanf("%d",&T);while(T--){
scanf("%d",&n);
for(i=1;i<=n;i++) pre[i]=fail[i]=1;
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=2;i<=n;i++)
if(a[i]>a[i-1]) fail[i]=fail[i-1]+1;
for(i=n-1;i>=1;i--)
if(a[i]<a[i+1]) pre[i]=pre[i+1]+1;
int ans=0;
for(i=0;i<=n;i++) Min[i]=inf;//最核心的一段代码
for(i=1;i<=n;i++){
int tmp=(lower_bound(Min+1,Min+i+1,a[i])-(Min+1));//lower_bound返回大于a[i]的第一个数的位置
ans=max(ans,pre[i]+tmp);
Min[fail[i]]=min(Min[fail[i]],a[i]);//贪心的思想,用min数组储存处理过后的a[i]数组
}
printf("%d\n",ans);
}
}