分金币

题目描述


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

输入


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

输出


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

样例输入

3
100
100
100
4
1
2
5
4

样例输出

0
4
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1000000+10;
long long aa[maxn], c[maxn];

int main()
{
    int n,i;
    int long long s,ans,m;
    while(scanf("%d",&n)!=EOF)
    {
        s=0;
        ans=0;
        for(i=1;i<=n;i++)
            {
                scanf("%lld",&aa[i]);
                s=s+aa[i];
        }
        m=s/n;   //m为平均每个人得到的金币
        c[0]=0;
        for(i=1;i<=n;i++)
            c[i]=c[i-1]+aa[i]-m;  //求出ci数组
        int long long x;
        sort(c,c+n);    //对数组ci排序(是为了找ci的中点)
        x=c[n/2];     //x为数组ci的中点,不管n是不是奇数,n直接除以2是没毛病的
        for(i=0;i<n;i++)
            ans=ans+abs(x-c[i]);  //ans为转手金币的最小值
        printf("%lld\n",ans);
    }
    return 0;
}

 思路:(我也不会,只能百度一波)

m为平均每个人的金币,数组aa用来存放每个人的金币。

数学思维:设第i个人有ai个金币,xi为给出去的金币,对1号:a1-x1(1号给4号的)+x2(2号给1号的)=m;对2号:a2-x2+x3=m....

对1:x2=m-a1+x1=x1-c1,令c1=a1-m;对2:x3=x2+m-a2,用x1代x2得到:x3=x1-(a2+c1-m)=x1-c2,c2=c1+(a2-m);以此类推(将每个人送出去的金币最后化为含x1的表达式),我们就可以得到ci的关系c[i]=c[i-1]+aa[i]-m(核心!!!!!)。

被转手的金币数量最小值=|x1|+|x1-c1|+|x1-c2|+|x1-c3|+....+|x1-cn|;即用数学方法得到转手金币数量的最小值=>找一个点x1,使得它到c1,c2,c3...cn距离之和最小=>x1为他们的中点。

 

posted @ 2018-08-11 15:31  RAIN-code  阅读(319)  评论(0编辑  收藏  举报