题目
数据范围
1≤N≤10^5,
0≤p_i,t_i≤10000
输入样例:
5
1 5 3 3 4
1 2 2 2 1
输出样例:
5
样例解释
一组最优的 Farmer John 可以使用的指令如下:
初始温度 :1 2 2 2 1
升高牛棚 2..5:1 3 3 3 2
升高牛棚 2..5:1 4 4 4 3
升高牛棚 2..5:1 5 5 5 4
降低牛棚 3..4:1 5 4 4 4
降低牛棚 3..4:1 5 3 3 4
题解
差分
差分:对于数列 a,其第 i 个元素和第 i - 1 个元素的差称为数列 a 第 i 项的差分。
有差分数组为 b,则存在:b[i] = a[i] - a[i - 1]
推导差分数组:
- 预处理:
b[i] = a[i] - a[i - 1]
- 对差分数组求前缀和可以得到原数列 a :
sumb[i] = b[1] + b[2] + ... b[i] = a[1] + a[2] - a[1] + ... + a[i] - a[i - 1] = a[i]
技巧:
- O(1)时间复杂度对数组 a[l…r] 的每一个元素加上 p:差分数组操作d
[l] += p, d[r+1] -= p
, 则对差分数组复原a数组时候就可以得到区间内都加p
题目思路
题意可以转化为:将两个温度数组求差得到arr数组,求对区间加一或者减一的最少操作次数得到全0的数组
- 区间加减法很容易就联系到差分数组
拟求得arr数组全0,则其差分数组也一定全0 :原因为,差分数组的实质为相邻两个数的差值,由于第一个数实际是和0做差分,则可以理解为差分数组全0 == 原数组第一个数与0的差值为0 == 原数组全为0
因此,我们每次可以从 差分数组b 中同时挑一个正数减 1,和一个负数加 1。也可以只挑一个正数减 1,或一个负数加 1
- 挑一个正数减 1,和一个负数加 1:相当于对arr数组一个区间加减1
- 只挑一个正数减 1,或一个负数加 1: 相当于对arr数组从某个位置及其后所有元素加减1
按照如此的操作方案,使得差分数组归0的操作次数为max(正数和,|负数和|)
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int main(){
int n;
cin>>n;
int arr[n+1];
memset(arr, 0, sizeof arr);
for(int i = 1; i <= n; i++){
cin>>arr[i];
}
// 获得每个牛栏位置的空调调整度数
for(int i = 1; i <= n; i++){
int b;
cin>>b;
arr[i] -= b;
}
// 完成差分,从后向前遍历获取差分
for(int i = n; i; i--){
arr[i] -= arr[i-1];
}
// 要使得空调度数arr数组全0,则差分数组也应当全为0
// 使得差分中正数位置减一,负数位置加一,则是完成一个区间[l,r]整体的减一
// 还可以对某一个位置直接加一、减一,相当于对从该位置开始往后的所有值都加减一
// 则要使得差分数组全变为0的次数是max(正数和,|负数和|)
int pos = 0, neg = 0;
for(int i = 1; i <= n; i++){
if(arr[i] > 0) pos += arr[i];
else neg -= arr[i]; // 用减法转化为绝对值后结果
}
cout << max(pos,neg) << endl;
return 0;
}