如果用O(n^2)是会TLE的,所以只能用O(nlogn)来做。
r[i]是以第i个元素为开头的最长连续递增子序列,l[i]是以第i个元素为结尾的最长连续递增子序列。
Min[i]是长度为i的最长连续递增子序列的最后一个元素的最小值。
Eg:若序列为6 5 4 3 2 1则Min[1]为1。
ans = max(ans, r[i] + len - 1 );为什么要减一,读者自己试一试就知道了。
for(int i = 1; i <= n; i++)
{
int len = lower_bound(Min+1, Min+1+n, a[i]) - Min; //Min+1是由于所有长度的最小值是一
ans = max(ans, r[i] + len - 1 );
Min[l[i]] = min(a[i], Min[l[i]]);
}
在这里,Min[]一定是从下标1开始由小至大更新值的,因为递增子序列的长度是递增的,只有出现了长度为1的连续递增子序列,才会出现长度为二的递增子序列。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define INF 0x3f3f3f3f;
using namespace std;
int a[10000000];
int l[10000000];
int r[10000000];
int Min[10000000];
int main()
{
//freopen("ztest.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
memset(r, 1, sizeof(r));
memset(l, 1, sizeof(l));
l[1] = 1;
int n;
scanf("%d",&n);
r[n] = 1;
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = n - 1; i >= 1; i--)
{
if(a[i+1] > a[i])
r[i] = r[i+1] + 1;
else
r[i] = 1;
}
for(int i = 2; i <= n ;i++)
{
if(a[i] > a[i-1])
l[i] = l[i-1] + 1;
else
l[i] = 1;
}
for(int i = 1; i <= n; i++)
{
Min[i] = INF;
}
int ans = 0;
for(int i = 1; i <= n; i++)
{
int len = lower_bound(Min+1, Min+1+n, a[i]) - Min;
ans = max(ans, r[i] + len - 1 );
Min[l[i]] = min(a[i], Min[l[i]]);
}
printf("%d\n",ans);
}
return 0;
}