题意:
给你一个序列,你只能消除其中连续的一段数,问消除完后剩下的序列中最长连续非严格上升子序列是多长。其实就是两个连续上升子序列的合并,问合并后最长的连续上升子序列是多少。
思路:
left[i]表示下标为i的数向左连续扩展的最远距离
right[i]表示下标为i的数向右连续扩展的最远距离
g[i]表示长度为i的连续上升子序列的最右端的那个数
首先,对于一个数a[i],以它为起点的最长上升子序列长度为right[i]
然后,在所有的g数组中找一个比a[i]小的长度最大(也就是下标最大)的g[i],这里a[i]<g[i],那么这个g[i]的长度(也就是i,这里定义一个k=i)就是另一个连续的上升子序列,即得到的两个上升子序列所拼接起来的长度为right[i]+k-1,然后不断地枚举a[i]并维护其长度取最大值就是答案了
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX=200005;
int n,a[MAX],g[MAX],left[MAX],right[MAX];
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
g[i]=INF;
}
right[n]=1;
for(int i=n-1;i>=1;i--){
if(a[i]>=a[i+1]) right[i]=1;
else right[i]=right[i+1]+1;
}
left[1]=1;
for(int i=1;i<=n;i++){
if(a[i]>a[i-1]) left[i]=left[i-1]+1;
else left[i]=1;
}
int ans=-1;
for(int i=1;i<=n;i++){
int k=lower_bound(g+1,g+1+n,a[i])-g;
ans=max(ans,right[i]+k-1);
if(a[i]<g[left[i]]) g[left[i]]=a[i];
}
printf("%d\n",ans);
}
return 0;
}