1 条题解

  • 0
    @ 2026-10-27 13:20:34

    思路与算法

    令平均数avg=sum(ai)/n,ci为前i个小朋友糖数减avg的累计差,取c0=0,共保留n个前缀值。设环上一条边净流量为z,其余边由守恒确定为z+ci或其相反号,总代价化为Σ|z+ci|。选择ci的中位数med,答案Σ|ci−med|。用nth_element选中位数。

    正确性说明

    每个人最终净收入为avg−ai,逐点写出流入减流出约束,可得到所有边流量仅剩一个自由整数z。每条边至少支付净流量绝对值;按净流方向安排传递可实现该代价,因为糖果守恒且可先从有余量的点传递。绝对值和的最小点为中位数:往右移动时左侧项增加、右侧项减少,只有两侧数量平衡才不再改善。因此所算是最小总代价。

    复杂度

    初始化与前缀O(n),nth_element平均O(n),汇总O(n),平均总O(n),空间O(n)。若改排序则为O(n log n)。

    易错点

    圆环不是线段,不能直接取固定前缀绝对值和;自由环流量必须优化。总数保证可整除,不可丢糖;n1答案0。前缀和与答案使用64位,修订ai上界下不会溢出。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        vector<long long> a(n), c(n);
        long long sum = 0;
        for (auto &x : a) {
            cin >> x;
            sum += x;
        }
        long long avg = sum / n;
        for (int i = 1; i < n; i++)
            c[i] = c[i - 1] + a[i - 1] - avg;
        nth_element(c.begin(), c.begin() + n / 2, c.end());
        long long med = c[n / 2], ans = 0;
        for (auto x : c)
            ans += llabs(x - med);
        cout << ans << '\n';
    }
    
    • 1

    信息

    ID
    2097
    时间
    1000ms
    内存
    64MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者