[AcWing 100] 增减序列

image
image

差分 + 贪心


点击查看代码
#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;
}

  1. 差分
    \(b_i = a_i - a_{i - 1}\)\(i \geqslant 2\)
  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\) 种取值
posted @ 2022-07-23 18:16  wKingYu  阅读(13)  评论(0编辑  收藏  举报