双端队列xLIS问题【栈】【最长不下降序列】

4 篇文章 0 订阅

>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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值