>Description
>解题思路
通过推算可以发现,对于原数列的第
i
i
i个数,一定是放在双端队列的中间,双端队列的左边和右边都为不下降序列(自动排除与答案无关的数),并且左边和右边的数在原数列中,都位于i的右边
再加上双端队列插入元素的规律,又可以神奇地发现,双端队列右边的数在原数列中的排列一样,而左边的数在原数列中是倒过来排序的(变成了最长不上升序列),
因此,u[i]为从i开始的最长不下降序列,d[i]为从i开始的最长不上升序列,ans=max(u[i]+d[i]-1)(去掉一个重复的i)
u[i]与d[i]预处理,本来我是dp处理,但是O(n^2)显然过不了,所以就要用栈+二分求最长不下降序列的方法,这样就只有O(nlogn)了
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100005
using namespace std;
int n, a[N], b[N], u[N], d[N], ans, s[N], t;
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
scanf ("%d", &a[i]);
for (int i = 1; i <= n; i++)
b[i] = a[n - i + 1]; //因为是求i~n的数,不太符合传统的1~i,所以我倒过来处理
for (int i = 1; i <= n; i++)
{
int l = lower_bound (s + 1, s + 1 + t, b[i]) - s;
s[l] = b[i];
if (l > t) t++;
u[i] = l; //注意这里是l!!!
}
for (int i = 1; i <= n; i++)
b[i] = -b[i]; //全部转换为负数以后,求最长不下降序列=求原数的最长不上升序列
memset (s, 0, sizeof (s));
t = 0;
for (int i = 1; i <= n; i++)
{
int l = lower_bound (s + 1, s + 1 + t, b[i]) - s;
s[l] = b[i];
if (l > t) t++;
d[i] = l;
}
for (int i = 1; i <= n; i++)
ans = max (ans, u[i] + d[i] - 1);
printf ("%d", ans);
return 0;
}