UVA 10534 Wavio Sequence(最长上升子序列O(nlogn))

本文详细介绍了如何使用O(nlogn)的LIS算法解决寻找一个序列中长度为2N+1的最长子序列问题,该子序列前N个元素递增,后N个元素递减。通过实例解释了贪心+二分查找的LIS算法原理,并提供了具体代码实现,旨在帮助读者理解算法核心思想并应用于实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:寻找一个最长(假设长度为2N+1)的子序列,使得前N个元素递增,后N个元素递减。


解析:一个找从前到后的上升子序列,另一个找从后到前的上升子序列。最后扫一遍,取两个状态之中较小的,即可找出最长的先上升后下降的子序列。可是如果用O(n^2)的算法会超时。所以要用O(nlogn)的LIS算法。


O(nlogn)的LIS算法(贪心+二分查找):
开辟一个栈,每次取栈顶元素s和读到的元素a做比较,如果a>s,则加入栈;如果a<s,则二分查找栈中的比a大的第1个数,并替换。最后序列长度为栈的长度。
这也是很好理解的,对x和y,如果x<y且E[y]<E[x],用E[x]替换  E[y],此时的最长序列长度没有改变但序列Q的"潜力"增大。 
举例:原序列为1,5,8,3,6,7  

栈为1,5,8,此时读到3,则用3替换5,得到栈中元素为1,3,8,  再读6,用6替换8,得到1,3,6,再读7,得到最终栈为1,3,6,7 ,最长递增子序列为长度4。 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100005;
int dp[N],dp2[N];
int a[N],st[N];
int main() {
	int n;
	while(scanf("%d",&n) != EOF) {
		for(int i= 0; i < n; i++) {
			scanf("%d",&a[i]);
		}
		int top = 0;
		for(int i = 0; i < n; i++) {
			if(top == 0 || a[i] > st[top-1]) {
				st[top++] = a[i];
			}else {
				st[(lower_bound(st,st+top,a[i]) - st)] = a[i];
			}
			dp[i] = top;
		}
		top = 0;
		for(int i = n-1; i >= 0; i--) {
			if(top == 0 || a[i] > st[top-1]) {
				st[top++] = a[i];
			}else {
				st[(lower_bound(st,st+top,a[i]) - st)] = a[i];
			}
			dp2[i] = top;
		}
		int ans = 0;
		for(int i = 0; i < n; i++) {
			ans = max(ans,min(dp[i],dp2[i])*2-1);
		}
		printf("%d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值