增减序列超详细题解.fjx


正确性证明

1. 最少操作次数为 max(x, y)
  • 差分序列的性质:对原序列 a 的区间 [l, r] 进行加 k 的操作,等价于对差分序列 b 中的 b[l]kb[r + 1]k(如果 r + 1 <= n)。要将原序列 a 变成所有元素都相等的序列,等价于将差分序列 bb[1] 外的所有元素都变为 0。
  • 操作策略:可以同时对正的差分和负的差分进行操作。每次操作可以选择一个正的差分和一个负的差分,将它们同时向 0 靠近。例如,有一个正的差分 b[i] 和一个负的差分 b[j],可以选择一个合适的 k,使得 b[i] 减去 kb[j] 加上 k,这样就可以同时减少两个差分的绝对值。
  • 操作次数分析:由于正的差分总和为 x,负的差分总和为 y,在尽量配对操作的情况下,当较小的一方(min(x, y))变为 0 时,剩下的操作次数就是较大的一方(max(x, y))。因此,最少操作次数为 max(x, y)
2. 最终序列可能的不同取值数量为 abs(x - y) + 1
  • 最终序列的取值与差分的关系:最终序列的取值取决于对 b[1] 的操作。在将差分序列 bb[1] 外的所有元素都变为 0 的过程中,对 b[1] 的影响是由剩余未配对的操作决定的。
  • 剩余操作的影响:当 x > y 时,最后剩下 x - y 次正的操作,这些操作可以作用在 b[1] 上,使得 b[1] 增加 0x - y 之间的任意整数;当 x < y 时,最后剩下 y - x 次负的操作,这些操作可以作用在 b[1] 上,使得 b[1] 减少 0y - x 之间的任意整数。因此,最终序列可能的不同取值数量为 abs(x - y) + 1

核心代码:

for (int i = 2; i <= n; i++) {
	b[i] = a[i] - a[i - 1];
	if (b[i] > 0) x += b[i];
	else y -= b[i];
}

最后只需要输出:

cout << max(x, y) << "\n" << abs(x - y) +1;
10 个赞

没有人点赞?难道我写的不好?
我写了好久呢

3 个赞

有的

2 个赞

写的不错诶

2 个赞

大佬orz%%%

2 个赞