[差分] P4552 [Poetize6] IncDec Sequence 题解
据说是一个相当经典的差分问题呢。
问题链接: P4552
看第一问。
首先是一个区间操作的转化。我们发现题目中的区间加减其实就是差分数组的单点加减。
也就是说他这个题目条件就转换成了,你单次操作可以在差分数组选两个位置一个加1一个减1,或者选单一个位置加1或减1,问你几次操作能让差分数组全是0。
是不是比较简单的贪心就能看出来了,首先把能同时消掉的给消了,剩下的就只能一个一个改。
我们假设差分数组中正数的和是 \(sum1\) , 负数和的相反数是 \(sum2\)。那你能一起消掉的就是 \(\min(sum1 , sum2)\) , 只能单独消掉的就是 \(\max(sum1 , sum2) - \min(sum1 , sum2)\)。
加一起答案就是 \(\max(sum1 , sum2)\)。
第二问。
事先声明,默认的前提是最终数组的元素都等于数组第一个元素。
考虑一下为啥会在步数最少的前提下,有不同的情况。
其实就是因为你修改一个差分数组的元素,实际可以有两种操作。
比如下面这个数组。
\[1 , 1 , 2 , 3 , 4
\]
差分数组是
\[0 , 1 , 1 , 1
\]
你要把第二个差分数组元素改成 0 , 那么你对实际数组的操作其实有两种做法。
一种是这么改
\[1 ,1 , 1 , 2 , 3
\]
一种是这么改
\[2 , 2 , 2 , 3 , 4
\]
也就是说,你每有一个单独的操作,你都可以选择该前面还是改后面,也就是是否改动第一个元素。这样,就让最终答案多了一种情况。
上文提到过单独消掉的操作个数是 \(\max(sum1 , sum2) - \min(sum1 , sum2)\) 个,因此第二问答案就是 \(\max(sum1 , sum2) - \min(sum1 , sum2) + 1\) , 加的那个 1 就是啥改动也不做。
#include <bits/stdc++.h>
#define int long long
constexpr int N = 1e5 + 5;
using namespace std;
int n , sum1 , sum2 , a[N] , d[N];
signed main() {
cin >> n;
for(register int i = 1; i <= n; ++i) {
cin >> a[i];
}
for(register int i = 1; i < n; ++i) {
d[i] = a[i + 1] - a[i];
if(d[i] < 0) sum1 += -d[i];
else sum2 += d[i];
}
cout << max(sum1 , sum2) << '\n' << max(sum1 , sum2) - min(sum1 , sum2) + 1;
return 0;
}