题意
有(n)个积木,给定它们的高度(h_i),每次可以将某一段区间中的所有高度减一,问最少操作多少次可以将所有高度变成(0)。
数据范围
(1 leq n leq 10^5)
(0 leq h_i leq 10000)
思路
构造差分序列:
[b_1 = a_1 \
b_2 = a_2 - a_1 \
b_3 = a_3 - a_2 \
dots \
b_n = a_n - a_{n - 1} \
b_{n + 1} = -a_n
]
若原序列全都变为(0),那么差分序列也全变成了(0)。因此原问题等价于每次从 (b_1,b_2,dots ,b_{n+1})中挑两个数,前一个减(1),后一个加(1),多少次操作可以将差分序列全变成(0)。
对于差分序列中每个正数 (b_i),要将其减为(0),最少需要操作 (b_i)次,因此总操作次数一定不少于差分数组中所有正数之和 (B)。
然后我们能够构造一种操作方式,使得恰好可以通过 (B) 次操作,将所有数变成(0)。 那么就可以说明最少操作次数一定是所有正数之和。
操作方式为:从后往前遍历,找到第一个整数,对其进行减(1)操作,其后必存在一个负数,对其进行加(1)操作。
对于每个正数(b_i),其后必存在一个负数,原因是对(b_i)及其往后的数字求和得到的是(-a_k < 0),因此必存在负数。
因此,最终答案就是差分数组中所有正数之和。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 100010;
int n;
int a[N];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
int ans = 0;
for(int i = 1; i <= n; i ++)
if(a[i] > a[i - 1])
ans += (a[i] - a[i - 1]);
printf("%d
", ans);
return 0;
}