题目link:https://www.acwing.com/problem/content/102/
对于此题,因为每个数都比较的大,所以差分进行处理。
设原数组为 $a[i]$ ,差分后数组为 $d[i]$ $=$ $a[i]$ $-$ $a[i$ $-$ $1]$。
则容易得出原题转换为:
- 给定一个数组 $d$,有下面两个操作:
- 将 $d[l]$ $+$ $1$ ,$d[r$ $+$ $1]$ $-$ $1$;
- 将 $d[l]$ $-$ $1$ ,$d[r$ $+$ $1]$ $+$ $1$;
- 求最少操作次数使得 $d[2]$ ~ $d[n]$ 全部变为 $0$ ,以及 $d[1]$ 的可能值的数量
设 $cntx$ 表示 $d$ 数组中的正数之和, $cnty$ 表示 $d$ 数组中负数之和。
根据贪心原理,容易得出当上文中第一个操作或第二个操作中的两个加减都能使序列更趋近于目标序列的话为最优,只使用其中一个加减为次。
考虑这个 $cntx$ 和这个 $cnty$ 最终都是要变成 $0$ ,因此可以使用两个操作之一将 $cntx$ 和 $cnty$ 互相抵消,容易得出需要操作 $min(cntx,cnty)$ 次。但当其中一方为 $0$ 时,另一方只能使用半个操作。
假设此时序列中除了 $0$ 就是负数,而第 $i$ 位为 $-1$ ,那么可以取 $l$ $=$ $i$ , $r$ $=$ $n$ 进行操作一或 $l$ $=$ $1$ , $r$ $=$ $i$ $-$ $1$ 进行操作二,最后不为 $0$ 的一方就用这种方法清 $0$ ,容易得出需要操作 $|cntx$ $-$ $cnty|$ 次。
此时题中第一问已经解决,考虑第二问。
$d[1]$ 的可能取值只与后面 $cntx$ 或 $cnty$ 为 $0$ 时进行的操作会改变。假设每次都是取 $l$ $=$ $1$ 然后要更新的数 $i$ 取 $r$ $=$ $i$ $-$ $1$ ,那么 $d[1]$ 的值就会改变一次。最多改变次数就为 $|cntx$ $-$ $cnty|$,但因为也可以不变(取 $l$ $=$ $i$,$r$ $=$ $n$ 操作)。所以 $d[1]$ 的可能值数量就为 $|cntx$ $-$ $cnty|$ $+$ $1$;
因此本题答案为:
- 第一问:$min(cntx,cnty)$ $+$ $|cntx$ $-$ $cnty|$ $=$ $max(cntx,cnty)$(至于这个$max$,很容易推出来,或者直接整体法考虑问题也可以不用前面的 $min$ $+$ 绝对值 导);
- 第二问:$|cntx$ $-$ $cnty|$ $+$ $1$;
代码把公式套进去就行了(别忘了会爆 $int$):
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 #define ll long long 4 using namespace std; 5 int n, a[100010], d[100010]; 6 ll cntx, cnty; 7 int main() 8 { 9 scanf("%d", &n); 10 for(int i = 1; i <= n; ++i) 11 scanf("%d", &a[i]), d[i] = a[i] - a[i - 1]; 12 for(int i = 2; i <= n; ++i) 13 cntx += (d[i] > 0) * d[i], cnty -= (d[i] < 0) * d[i]; 14 printf("%lld %lld", max(cntx, cnty), abs(cntx - cnty) + 1); 15 return 0; 16 }