分析
题意: 每次可以指定一个连续区间数值加一,问至少多少次能达到给出的目标序列。
转换一下,只要求将目标序列全变成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;
}