花匠(最长波浪子序列——DP + 权值线段树)

本文介绍了一种求解最长波浪子序列的算法,通过动态规划和权值线段树优化,解决花匠栋栋如何选择部分花留下的问题,以满足特定的波浪形排列条件。

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

题目描述

花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。
具体而言,栋栋的花的高度可以看成一列整数 h 1 ℎ_1 h1, h 2 ℎ_2 h2, … … , h n ℎ_n hn。设当一部分花被移走后,剩下的花的高度依次为 g 1 g_1 g1, g 2 g_2 g2, … … , g n g_n gn,则栋栋希望下面两个条件中至少有一个满足:
条件 A A A:对于所有的 i i i g 2 i g_{2i} g2i > g 2 i − 1 g_{2i-1} g2i1,且 g 2 i > g 2 i + 1 g_{2i}>g_{2i+1} g2i>g2i+1
条件 B B B:对于所有的 i i i g 2 i &lt; g 2 i − 1 g_{2i}&lt;g_{2i-1} g2i<g2i1,且 g 2 i &lt; g 2 i + 1 g_{2i}&lt;g_{2i+1} g2i<g2i+1
注意上面两个条件在 m = 1 m = 1 m=1时同时满足,当 m &gt; 1 m &gt; 1 m>1时最多有一个能满足。
请问,栋栋最多能将多少株花留在原地。

输入

输入的第一行包含一个整数n,表示开始时花的株数。
第二行包含n个整数,依次为 h 1 ℎ_1 h1, h 2 ℎ_2 h2, … … , h n ℎ_n hn,表示每株花的高度。

输出

输出一行,包含一个整数

样例输入

5 5 5
5 5 5 3 3 3 2 2 2 1 1 1 2 2 2

样例输出

3 3 3

提示

【输入输出样例说明】

有多种方法可以正好保留 3 株花,例如,留下第 1、4、5 株,高度分别为 5、1、2,满足条件 B。


【数据范围】

对于 20 20 20%的数据, n ≤ 10 n ≤ 10 n10
对于 30 30 30%的数据, n ≤ 25 n ≤ 25 n25
对于 70 70 70%的数据, n ≤ 1000 n ≤ 1000 n1000 0 ≤ h i ≤ 1000 0 ≤ ℎ_i≤ 1000 0hi1000
对于 100 100 100%的数据, 1 ≤ n ≤ 100 , 000 1 ≤ n ≤ 100,000 1n100,000 0 ≤ h i ≤ 1 , 000 , 000 0 ≤ ℎ_i≤ 1,000,000 0hi1,000,000,所有的 h i ℎ_i hi 随机生成,所有随机数服从某区间内的均匀分布。


题目有点长,说白了就是求原序列的最长波浪子序列
我们可以借鉴求最长上升子序列 ( L I S ) (LIS) LIS的方法,先想一个 1 D / 1 D 1D/1D 1D/1D D P DP DP
状态: f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1]表示以 i i i为结尾的最长波浪子序列的长度,且 a [ i ] a[i] a[i]是峰/谷
f [ i ] [ 0 ] = m a x ( f [ j ] [ 1 ] + 1 ) f[i][0] = max(f[j][1] + 1) f[i][0]=max(f[j][1]+1)
f [ i ] [ 1 ] = m a x ( f [ j ] [ 0 ] + 1 ) f[i][1] = max(f[j][0] + 1) f[i][1]=max(f[j][0]+1)
( 1 ≤ j < i ) (1≤j<i) (1ji)
初值: f [ i ] [ 0 / 1 ] = 1 f[i][0/1] = 1 f[i][0/1]=1
终值: m a x ( f [ i ] [ 0 / 1 ] ) max(f[i][0/1]) max(f[i][0/1])


然后我们非常开心的发现它超时了o( ̄︶ ̄)o


好,我们现在来用牛刀 (权值线段树) 杀只鸡
b [ i ] [ 0 / 1 ] b[i][0/1] b[i][0/1]表示以值为 i i i为结尾的且 i i i为峰/谷的最长波浪子序列长度那么只要维护这个 b b b数组即可
f [ i ] [ 0 ] = m a x ( b [ j ] [ 1 ] + 1 ) ( 0 ≤ j < i ) f[i][0]=max(b[j][1]+1)(0≤j<i) f[i][0]=max(b[j][1]+1)(0ji)
f [ i ] [ 0 ] = m a x ( b [ j ] [ 0 ] + 1 ) ( i < j ≤ m a x h ) f[i][0]=max(b[j][0]+1)(i<j≤maxh) f[i][0]=max(b[j][0]+1)(ijmaxh)
权值线段树区间查询,单点修改,轻松。

#include<cstdio>
using namespace std;
const int maxn = 100005;
const int maxh = 1000000;
int a[maxn] , f[maxn][2];
inline int max(int x , int y){return x > y ? x : y;}
inline int read()
{
	char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	int res = 0;
	while(ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + (ch ^ 48) , ch = getchar();
	return res;
}
struct ST
{
	private:
		int tree[maxh << 2][2];
	public:
		void change(int p , int l , int r , int x , int k , int id)
		{
			if(l == r)
			{
				tree[p][id] = max(tree[p][id] , k);
				return;
			}
			int mid = (l + r) >> 1;
			if(x <= mid) change(p + p , l , mid , x , k , id);
			else change(p + p + 1 , mid + 1 , r , x , k , id);
			tree[p][id] = max(tree[p + p][id] , tree[p + p + 1][id]);
		}
		int query(int p , int l , int r , int x , int y , int id)
		{
			if(x > y) return 0;
			if(l == x && r == y) return tree[p][id];
			int mid = (l + r) >> 1;
			if(y <= mid) return query(p + p , l , mid , x , y , id);
			else if(x > mid) return query(p + p + 1 , mid + 1 , r , x , y , id);
			else return max(query(p + p , l , mid , x , mid , id) , query(p + p + 1 , mid + 1 , r , mid + 1 , y , id));
		}
}st;
int main()
{
	int n = read();
	for(int i = 1;i <= n;i++) a[i] = read();
	f[1][0] = f[1][1] = 1;
	st.change(1 , 0 , maxh , a[1] , 1 , 0);
	st.change(1 , 0 , maxh , a[1] , 1 , 1);
	for(int i = 2;i <= n;i++)
	{
		f[i][0] = st.query(1 , 0 , maxh , 0 , a[i] - 1 , 1) + 1;
		f[i][1] = st.query(1 , 0 , maxh , a[i] + 1 , maxh , 0) + 1;
		st.change(1 , 0 , maxh , a[i] , f[i][0] , 0);
		st.change(1 , 0 , maxh , a[i] , f[i][1] , 1);
	}
	int ans = 0;
	for(int i = 1;i <= n;i++) ans = max(ans , max(f[i][0] , f[i][1]));
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值