一道关于差分的题目
田小锋有n个盒子,这个B想要在这n个盒子放入一定量的球。一开始n个盒子是空的,接下来每次操作,这个B可以选择一段连续区间[L,R],然后在第L个盒子到第R个盒子之间每个盒子都放入一个球(含第L个和第R个玻璃瓶),求能达到符合的要求的最少的操作次数。
输入格式:
第一行包含一个整数 n(1≤n≤110),表示n个盒子。
第二行包含 n 个整数,表示每个盒子要求要放的球个数m。 0≤m≤10000
输出格式:
仅一行,即所需的最少操作数。
输入样例:
5
2 3 4 1 2
输出样例:
5
(解释:
操作1:[1,5]区间放一个
操作2:[1,3]区间放一个
操作3:[2,3]区间放一个
操作4:[3,3]区间放一个
操作5:[5,5]区间放一个,放的方法不唯一,但是最少操作次数是5次)
思路:差分
这个是样例的数据:
下面只看下标1-5的
最开始的时候全部的盒子都是空的,即差分数组元素全部都是0。那么我们反过来推导,让上图中的差分数组经过操作全部变成0.
重要的一点:此题中差分数组正数之和是绝对大于等于负数之和的,为什么呢?因为差分数组的前缀和数组就是hezi数组里面的元素值,盒子里面的球的个数是>=0的,这样一来,此题中差分数组正数之和是绝对大于等于负数之和的。
对区间[L,R]操作全部加一或者减一,对应的差分数组就是c[L]+(-)1,c[R+1]-(+)1。这个应该不用多说。
我们再来看差分数组:2 1 1 -3 1. 最少操作次数让它全部变成0,前面加一,对应的后面就要减一,反之亦然。又因为此题中差分数组正数之和是绝对大于等于负数之和的,我们可以让负数和正数抵消掉,每次抵消1也算作一次操作,所以我们只算出差分数组中正数之和就行了。
上图中,2,1可以和-3抵消,剩下的数组元素就是0 0 1 0 1,(对应的盒子中就是0 0 1 1 2),然后[3,5]减一,由于5+1超界了,就不算了呗,所以[3,5]减一后就是0 0 0 0 1(盒子中0 0 0 0 1),然后[5,5]减一,最后变成了0 0 0 0 0就行了,所以差分数组中剩下的全部是正数的时候,我们就[L,N]区间来操作,N是数组最大的下标。最后总结看就是把正数加起来就行了嘛。
#include <iostream>
using namespace std;
const int N = 1e5+5;
int num[N], n, ans = 0, c[N];
int main()
{
cin >> n;
for ( int i = 1; i <= n; ++i ) {
cin >> num[i];
c[i] = num[i] - num[i-1];
}
// for ( int i = 1; i <= n; ++i ) {
// cout << c[i] << " ";
// }
// cout << '\n';
for ( int i = 1; i <= n; ++i ) {
ans += c[i] >= 0 ? c[i] : 0;
}
cout << ans << endl;
return 0;
}