VUa 11300.Spreading the Wealth【RujiaLiu随书练习】【10月6】

Spreading the Wealth

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

【样例输入】

3

100

100

100

4

1

2

5

4

【样例输出】

0

4


令M为总金币的平均数,假设对于第i个人,原金币有A[i]个,他给前一个人x个金币,后一个人给他y个金币,则A[i]-x+y=M。

对于第1个人,A1-x1+x2=M → x2=x1-C1 (令C1=A1-M)

对于第2个人,A2-x2+x3=M →x3=M-A2+x2 → x3=x1-C2       (C2=C1+A2-M)

对于第3个人,同理的 x4=x1-C3   (C3=C2+A3-M)

我们希望所有的xi的绝对值之和最小,即|x1|+|x1-C1|+|x2-C2|+——+|x1-Cn-1|(即在数轴上找一点使得到各点Ci距离之和最小的点,这个点就是所有Ci的中位数(证明请参考刘汝佳的训练指南))

代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=1000005;
long long A[maxn],point[maxn];
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        long long sum=0,M,x,ans=0;
        for(int i=0;i<n;i++){
            scanf("%lld",&A[i]);
            sum+=A[i];
        }
        M=sum/n;
        point[0]=0;
        for(int i=1;i<n;i++)
            point[i]=point[i-1]+A[i]-M;
        sort(point,point+n);
        x=point[n/2];
        for(int i=0;i<n;i++)
            ans+=abs(x-point[i]);
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值