【题解】 UVa11300 Spreading the Wealth

题目大意

圆桌旁边坐着\(n\)个人,每个人有一定数量的金币,金币的总数能被\(n\)整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数量相等。您的任务是求出被转手的金币的数量的最小值。

Solution

考虑一下这个东西怎么做,假设每一个人向周围都可以传递对吧,设\(x_i\)表示\(i\)\(i-1\)传递的金币数量,那么\(x_1\)就是\(1\)\(n\)传递的金币数量,那么接下来我们考虑这个东西本质是什么?

设每一个人一开始有\(a_i\)个金币,那么显然,\(a_i+x_{i+1}-x_i=M\)(M为\(sum/n\))。我们要最小化\(\sum_{i=0}^{n-1}|x_i|\)

我们把这个转换一下:

\(x_i=a_i+x_{i+1}-M\)

但是这个是不好转换的,所以考虑通过\(i\)\(i+1\)的贡献。

\(x_{i+1}=M+x_i-a_i\)

所以进一步转换就是
\[ x_i=M+x_{i-1}-a_{i-1}; \]
那么我们再一次思考一下,是不是这个东西和数学中的中位数很像啊(想一想,为什么?)

\(c_i=\sum_{j=1}^{i-1}a_j-M\)

那么\(c_i=c_{i-1}+a_i-M\)

然后答案就是什么呢?

\(x_i=abs(x_1-c_{i-1})\)

显然就是中位数了。

然后就可以维护了。

//|--------------------------------|\\
//|author:Biscuit46                |\\
//|mail:m18890085125@163.com       |\\
//|Time:2018.10.29 16:33           |\\
//|Link:www.cnblogs.com/Biscuit46  |\\
//|--------------------------------|
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#define ll long long
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
using namespace std;
inline int gi(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
inline ll gl(){
    ll sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
const int N=1000010;
long long a[N],C[N];
int main(){
    int i,j,n,m,k;
    while(scanf("%d",&n)==1){
        ll tot=0;
        for(i=0;i<n;i++)
            a[i]=gl(),tot+=a[i];
        ll M=tot/n;C[0]=0;
        for(i=1;i<n;i++)
            C[i]=C[i-1]+a[i]-M;
        sort(C,C+n);
        long long x=C[n/2],ans=0;
        for(i=0;i<n;i++)
            ans+=abs(x-C[i]);
        printf("%lld\n",ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/biscuit46/p/9874659.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值