AcWing 糖果传递

这题的详解比较漫长,建议直接看<<指南>>.

这里面的思维量还是不小的,犹如在做一道精巧的数学证明题,实际上这就是数学证明题.

我目前当然还没有实力能够独立证明出这样的结论.

 

简化为模型记忆一下:

Q:有n人围坐一圈,第i个人手中有a[i]张纸牌,现在他们需要在相邻的人之间传递纸牌,相邻的人传递一张纸牌的代价为1,求解使得最终所有人手中的纸牌数量相等所需要的最小代价.(假设数据有解,即a[i]之和为n的整数倍).

A:设a[i]之和即总纸牌数为T,将所有a[i]减去T / n,之后求a[i]前缀和,设为s[i].

现在对s[i]进行排序以便取中位数s[(n + 1) / 2],计算出:

Σi=1n abs(s[i] - s[(n + 1) / 2])

即为答案.

 

代码倒是很短.

注意从在排序后的1~n个数中,中位数在第(n + 1) / 2个.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;

int n, s[1000010];
long long t, ans;

int main(){
    scanf("%d", &n);
    for(int i = 1;i <= n; i++){
        scanf("%d", s + i);
        t += s[i];
    }
    for(int i = 1; i <= n; i++) s[i] += s[i - 1] - t / n;
    sort(s + 1, s + 1 + n);
    int mid = s[(n + 1) >> 1];
    for(int i = 1; i <= n; i++) ans += abs(s[i] - mid);

    printf("%lld\n", ans);

    return 0;
}

 

posted @ 2020-12-26 22:10  goverclock  阅读(73)  评论(0编辑  收藏  举报