分金币

分金币

题目描述:

​ 圆桌旁坐着n个人,每人有一定数量的金币,金币总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数相等。你的任务是求出被转手的金币数量的最小值。比如,n=4,且4个人的金币数分别为1,2,5,4时,只需转移4枚金币(第3个人给第2个人两枚金币,第2个人和第4个人分别给第1 个人1枚金币)即可实现每人手中的金币数目相等。

Input:

​ 输入包含多组数据。每组数据第一行为整数n(n<=1 000 000),以下n行每行为一个整数,按逆时针顺序给出每个人拥有的金币数。输入结束标志为文件结束符(EOF)。

Output:

​ 对于每组数据,输出被转手金币数量的最小值。输入保证这个值在64位无符号整数范围内。

Sample Input:

4 1 2 5 4

Sample Output:

4

题解:

假设M为每个人都拥有的金币数,每个人的金币变化是左右相邻的人对其造成的影响
假设这n个人构成一个环,先假设n=4,设(x1)指1号给4号多少金币,则(x2)代表2号给1号
多少金币,其他的由此类推下去。
则对于1号来说,他给了4号金币,则剩(a1-x1)
2号给了他金币,则剩(a1-x1+x2)
注意这里1号给4号和4号给1号的意义隐含在x1的符号里面(很巧妙),其他的类似
由于最后要等于M,然后就可以得方程了
(a1-x1+x2=M >> x2 = x1-(a1-M) = x1 - C1\ a2-x2+x3=M >> x3 = x2-(a2-M)=x1-a1-a2-2*M = x1 - C2\ a3-x3+x4=M >> x4 = x3-a1-a2-a3-3*M = x1 - C3\ an-xn+x1=M >> xn = x1 - C(n-1))
看到这里我们知道答案是所有xi的绝对值最小了
很显然这就转化为数轴上求一点x到(ci)距离和的最小值,然而这个点x其实就是序列(ci)(排
序后)的中位数,稍微想想应该知道

代码:

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

const int maxn = 1000000+10;
long long A[maxn], C[maxn], tot, M;

int main(){
    int n;
    long long sum = 0;
    scanf("%d", &n);

    for(int i = 1; i <= n; ++i){
        scanf("%d", &A[i]);
        sum += A[i];
    }

    int arg = sum/n;

    C[0] = 0;

    for(int i = 1; i < n; ++i){
        C[i] = C[i-1] + A[i] - arg;
    }

    sort(C, C+n);

    long long x1 = C[n/2];
    long long ans = 0;

    for(int i = 0; i < n; ++i){
        ans += abs(x1 - C[i]);
    }

    printf("%lld
", ans);
    return 0;
}

结论:

给定数轴上的n个点,在数轴上的所有点中,中位数离所有顶点的距离之和最小。

原文地址:https://www.cnblogs.com/zcxhaha/p/10358545.html