【洛谷P1969】积木大赛

在这里插入图片描述

分析

题意: 每次可以指定一个连续区间数值加一,问至少多少次能达到给出的目标序列。
转换一下,只要求将目标序列全变成0的次数就行。

这道题最初的想法是很正确的,就是跟上升段有关。整个数列可以划分为若干个上升段,每个上升段推平的时间就是最后一个数的大小。

先考虑单独推平所有上升段的用时,就是所有上升段的末尾的值的和,我们统计为s2。但是有些是可以合并推平的啊,对于相邻的两个段来讲,他与前面那个段能合并一起推平的次数就是这个段开头那个数的值,那如果有连续好几个段呢?其实已经统计进去了,自行模拟一下减的次数就行了。所以我们统计这个量,记为s1。最后,对于 a [ n ] a[n] a[n] 的统计,发现 a [ n ] a[n] a[n] 一定是某个上升段的末尾,但不一定是开头。然而我们在循环的时候可以统计到n是上升段开头的情况,不能统计上升段末尾的n。所以最后的答案就是 s 2 + a [ n ] − s 1 s2+a[n]-s1 s2+a[n]s1

UPD:第二种思路,只关心上升的时候的差值统计答案即可,因为下降的段一定会被最高的“山峰”给一起减去了。

上代码

短小精悍
思路1code:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int n,a[100010],ans,s1,s2;

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&a[i]);
		if(a[i]<a[i-1]) s1+=a[i],s2+=a[i-1];
	} 
	cout<<s2+a[n]-s1;
	return 0;
} 

思路2 code:更短小精悍

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int n,a[100010],ans;

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&a[i]);
		if(a[i]>a[i-1]) ans+=a[i]-a[i-1];
	} 
	cout<<ans;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值