UVA 10534wavio sequence 波浪子序列

本文探讨了如何求解一个整数序列中最长的特殊子序列,该子序列需包含2k+1个元素,其中前k个元素递增,后k个元素递减。通过分析最长递增子序列(LIS)和最长递减子序列,采用动态规划和二分搜索优化算法,实现了高效求解。

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

题目大意:
给定一个长度为n整数序列求一个最长子序列,长度为2k+1,要求前k个上升,后k个数下降
分析
对这样一个整数序列分别求最长上升序列和最长下降序列然后对同一点进行相加求最大;
这个题目的重点时LIS问题参考刘汝佳的蓝书
如何求LIS,最笨的方法,我们用d(i)表示从0-i个整数序列的最长上升序列用P数组保存序列
状态转移方程为;
d(i)=max{d(j)|1<j<i且p(j)<p(i)}+1
核心代码

int maxp=0;
for (int i = 0; i < n; i++) {
	d[i] = 0;
	for (int j = 0; j < i; j++)
		if(p[j]<p[i])
			d[i] = max(d[i], d[j]+1);
	maxp=max(maxp,d[i]);
}

我们可以接着优化
对于两个状态a和b有Pa<Pb且d(a)=d(b)那么在之后的i状态a一定不会比b差-----------如果b满足Pb<Pi,那么a一定满足,反之却不成立,换句话说如果我们只保留a一定不会丢失最优解.
所以对于相同的d值我们只保留P中那最小的一个值 我们用g(i)表示,对于g数组而言,下标表示d值,下标所对应的g值是我们保存 的相同d值中最小的P值;对于g数组而言,元素一定是有序的,所以我们采取二分搜索查下标获取d值

for (int i = 1; i <= n; i++)     g[i] = Inf;		//别忘了初始化
for (int i = 0; i < n; i++) {
	int k = lower_bound(g + 1, g + 1 + n, P[i]) - g;
	d[i] = k;
	g[k] = P[i];
}

好了,言归正传,说我们这个题目
分析如上,上代码

#include<iostream>
#include<algorithm>
#include<string.h>
#define maxn 10000+10
#define Inf 0x3f3f3f3f	
using namespace std;

int n;
int q[maxn], d1[maxn], d2[maxn],g[maxn];

int main()
{
	while (cin >> n) {
		for (int i = 0; i < n; i++) 
			cin >> q[i];

		memset(g, Inf, sizeof(g));
		for (int i = 0; i < n; i++) {			//构造递增子序列
			int k = lower_bound(g, g + n, q[i]) - g;
			d1[i] = k;
			g[k] = q[i];
		}

		memset(g, Inf, sizeof(g));
		for (int i = n-1; i >=0; i--) {			//构造递减子序列
			int k = lower_bound(g, g + n, q[i]) - g;
			d2[i] = k;
			g[k] = q[i];
		}
		int ans = 0;
		for (int i = 0; i < n; i++) {			//求解最大值;
			if (d1[i]==d2[i])
			{
				ans = max(ans, d1[i] + d2[i]+1);
			}
		}

		cout << ans << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值