UVa11300

题目名称:Spreading the Wealth

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2275

 F. Spreading the Wealth 

Problem

A Communist regime is trying to redistribute wealth in a village. They have have decided to sit everyone around a circular table. First, everyone has converted all of their properties to coins of equal value, such that the total number of coins is divisible by the number of people in the village. Finally, each person gives a number of coins to the person on his right and a number coins to the person on his left, such that in the end, everyone has the same number of coins. Given the number of coins of each person, compute the minimum number of coins that must be transferred using this method so that everyone has the same number of coins.

The Input

There is a number of inputs. Each input begins with n(n<1000001), the number of people in the village. n lines follow, giving the number of coins of each person in the village, in counterclockwise order around the table. The total number of coins will fit inside an unsigned 64 bit integer.

The Output

For each input, output the minimum number of coins that must be transferred on a single line.

Sample Input

3
100
100
100
4
1
2
5
4

Sample Output

0
4


题目大意:有 n 个人围成一个圈,每个人都有一些金币,每个人可以给他左右的人一些金币,问都拥有相同金币时需要转手多少金币


思路:这道题刚看时,丫的一点思路都没有。如果有编号为 1,2,3,4 四个人,如果 1 给 2 三个金币,2 给 1 五个金币,这相当于 2 给 1 两个金币,1 没给 2,所以可以设 s2 表示 2 给 1 的金币数。。。注意 s1 是表示 1 给 4 的金币数,设编号为 1 的人初始金币为 a1,他给 4 s1个金币,2 给他 s2 个金币,即后来的金币数为 M = a1 - s1 + s2,同理 M = a2 - s2 + s3...

第一个人: s2 = M - a1 + s1 = s1 - c1  (设c1=a1-M,下同)

第二个人: s3 = M - a2 + s2 = 2M - a1 - a2 + s1 = s1 - c2

第三个人 :s4 = M - a3 + s3 = 3M - a1 - a2 - a3 + s1 = s1 - c3

...

我们希望所有 s 值的和最小,即 |s1| + |s1-c1| + |s1-c2| + |s1-c3| +...我们可以看到 |s1-ci| 不就是从几何上表示 s1 到 ci 的距离么??所以 s1 的最优解就是这些数 ci 的中位数(自己动手画下图,移动下点可以看出,如果s1在c1处,向右移动,左边的距离加的比右边距离减少的少,说明向右移变小,同理,左移也一样,所以选中位数最小)


代码如下:

<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
long long n,a[1000005],c[1000005];
int main()
{
    while(~scanf("%d",&n))
    {
        long long sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum+=a[i];
        }
        long long m=sum/n;
        c[0]=0;
        for(int i=1;i<n;i++)
            c[i]=c[i-1]+a[i]-m;
        sort(c,c+n);
        long long x=c[n/2],tot=0;
        for(int i=0;i<n;i++)
            tot+=abs(x-c[i]);
        printf("%lld\n",tot);
    }
    return 0;
}</span>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值