双端队列×LIS问题

双端队列×LIS问题 ⁡ \operatorname{双端队列×LIS问题} ×LIS

题目链接: S S L 比 赛   1480 SSL比赛\ 1480 SSL 1480

题目

在这里插入图片描述

输入

在这里插入图片描述

输出

在这里插入图片描述

样例输入

在这里插入图片描述

我来让你复制:
8
1 9 2 6 8 1 7 1926817

样例输出

在这里插入图片描述

我来让你复制:
5

样例解释

在这里插入图片描述

数据范围

在这里插入图片描述

思路

这道题是一道最长上升 & \& & 下降子序列。

我们可以发现,我们把从前面插入的数在原来的序列找出来,可以发现它包含了最长下降子序列。同理,我们把从后面插入的数在原来的序列找出来,可以发现它包含了最长上升子序列。
再一看,我们可以发现这两个序列的数合起来,看他们在答案序列的位置,就发现包含这个序列的最长上升子序列。

但是我们发现会有重复的地方,但是又因为数不相等,就有且只有一个重复的。

那我们就用 O ( n l o g n ) O(nlogn) O(nlogn) 的方法求出最长上升子序列和最长下降子序列,我们就枚举重合的那个数,找到包含这个数的最长上升子序列和最长下降子序列,找到最大的那个。最后减一输出就可以了。

提醒:要用快读吧。。。
(好像)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

int n, a[100001], b[100001], c[100001];
int ans1[100001], ans2[100001], ans;

int read() {//快读
	int re = 0, zhengfu = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') zhengfu = -zhengfu;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		re = re * 10 + c - '0';
		c = getchar();
	}
	return re * zhengfu;
}

int main() {
	n = read();//读入
	for (int i = 1; i <= n; i++) {
		a[i] = read();//读入
		b[n - i + 1] = a[i];//记录
	}
	
	for (int i = 1; i <= n; i++) {//最长上升子序列
		int now = lower_bound(c + 1, c + c[0] + 1, b[i]) - c;
		c[now] = b[i];
		if (now > c[0]) c[0]++;
		ans1[n - i + 1] = now;
	}
	
	for (int i = 1; i <= n; i++)//取反记录
		b[i] = -a[n - i + 1];
	memset(c, 0, sizeof(c));
	
	for (int i = 1; i <= n; i++) {//最长下降子序列
		int now = lower_bound(c + 1, c + c[0] + 1, b[i]) - c;
		c[now] = b[i];
		if (now > c[0]) c[0]++;
		ans2[n - i + 1] = now;
	}
	
	ans = 1;
	for (int i = 1; i <= n; i++)//找到答案
		ans = max(ans, ans1[i] + ans2[i] - 1);
	
	printf("%d", ans);//输出
	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值