p13595 贪心

题目描述

题目描述实在太猎奇了,解释一下题目到底要干嘛。

有n个数,其中每个数互不相同,你可以使值为x的数变成y,两个一样的数可以看一个区间,但代价是|x-y|,你要使所有区间覆盖整个数组。

举个例子

按照体面描述来解释

5
1 4 3 2 5

输出 2

那么首先这个二是哪里来的

第一次调整:选择 x=1,y=2,调整度为 1,旋律变为 2,4,3,2,5。

第二次调整:选择 x=4,y=5,调整度为 1,旋律变为 2,5,3,2,5。

所有调整结束后,位置 1 和位置 4 之间的音符产生共鸣,位置 2 和位置 5 之间的音符产生共鸣,所有音符都至少产生一次共鸣,调整度之和为 2。

那也就是说形成了两个区间,一个是1-4,一个是2-5

这两个区间确确实实覆盖了整个数组

那我们到底是要选哪些区间。

思路

利用贪心思想,我们尽可能不用修改,知道迫不得已,不选就要缺的时候才去修改。

那怎么修改又成了一个问题。

我们深入思考,就会发现,产生共鸣的音符一定是旋律差值是1的

证明

假如有这样一个序列

1 4 2 5 3

我们以直接将1改为3,这样就可以从头到尾一次性覆盖了,但你可别忘了,这个序列的每个数是不重复的。并且1~n每个数都会出现一次。所以我们一样可以将1 3的区间改成1到2,2到3的区间,代价是一样的。所以我们只考虑旋律差值为1的旋律去共鸣。

这时候思路就清晰很多了。代码实现。

这时候我们可以拿一个变量mr,代表1~mr都覆盖了,如果我们这时遍历到i,但是i<=mr,我们该不该选i这个节点去产生共鸣。不能,我们不确定他是否要用得上。只要不是100%能用上的,我们坚决不用。

那什么时候才是100%能用上的呢

就是i>mr的时候,我们就必须要选了

but

不一定是选第i个旋律去共鸣

我们要用一个变量r去保存从1~i产生共鸣(代价为1)可以覆盖最右边的数,使mr=r(更新覆盖至最右边)

没次产生共鸣的时候,ans++

最后输出ans为答案即可

代码

#include<bits/stdc++.h>
using namespace std;
long long n,mr,ans;
long long a[10000010],b[10000010];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		b[a[i]]=i;
	}
	long long r=0;
	for(int i=1;i<=n;i++)
	{
		r=max({b[a[i]-1],b[a[i]+1],r});
		if(mr<i)
		{
			ans++;
			mr=r;
		}
	}
	cout<<ans;
	return 0;
}
posted @ 2026-03-23 21:27  RONNY_D  阅读(2)  评论(0)    收藏  举报