[AcWing 100] 增减序列
差分 + 贪心
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n;
int a[N], b[N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 2; i <= n; i ++)
b[i] = a[i] - a[i - 1];
LL p = 0, q = 0;
for (int i = 2; i <= n; i ++) {
if (b[i] > 0)
p += b[i];
else
q -= b[i];
}
cout << max(p, q) << endl;
cout << abs(p - q) + 1 << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
return 0;
}
- 差分
\(b_i = a_i - a_{i - 1}\) (\(i \geqslant 2\)) - 贪心
\(a_1\) 到 \(a_n\) 相等时,需要满足两个条件:
① \(b_2\) 到 \(b_n\) 都为 \(0\)
② \(b_1\) 是最终 \(a_1\) 到 \(a_n\) 的值
最少的操作次数就是使得 \(b_2\) 到 \(b_n\) 都为 \(0\) 的最少操作次数,最终结果的个数就是 \(b_1\) 的可能取值
在 \([L, R]\) 区间同时加上 \(1\),对应在差分数组上,\(b_L = b_L + 1\),\(b_{R + 1} = b_{R + 1} - 1\)(减法类似),考虑以下四种情况:
① \(2 \leqslant L \leqslant R \leqslant n - 1\),此时 \(R + 1 \leqslant n\),效果是让 \(b_2\) ~ \(b_n\) 中的一个数加一,另一个数减一
② \(L = 1\),\(R \leqslant n - 1\),此时 \(R + 1 \leqslant n\),效果是让 \(b_1\) 加(减)一,\(b_2\) ~ \(b_n\) 中的一个数减(加)一
③ \(L \geqslant 2\),\(R = n\),此时 \(R + 1 = n + 1\),效果是让 \(b_{n + 1}\) 加(减)一,\(b_2\) ~ \(b_n\) 中的一个数减(加)一
④ \(L = 1\),\(R = n\),对差分数组无影响,肯定不是最少操作次数需要的,排除这种操作
设所有 \(b_i > 0\) 的和为 \(p\),所有 \(b_i < 0\) 的和为 \(q\),要想满足操作次数最小,首先尽可能多使用 ① 操作,让 \(p\) 和 \(q\) 其中一个变为 \(0\),再使用 ② 或 ③ 操作使得不为 \(0\) 的那个变为 \(0\)
最小操作次数应为 \(min(p,q) + |p - q| = max(p, q)\)
在 \(p\) 和 \(q\) 其中一个变为 \(0\) 后,用 ② 会使 \(b_1\) 加一,用 ③ 不会改变 \(b_1\),一共要使用 \(|p - q|\) 次 ② 或 ③ 操作,可以有 \(0\) 次,\(1\) 次,\(\cdots\),\(|p - q|\) 次选择 ②,\(b_1\) 最终有 \(|p - q| + 1\) 种取值