您的位置:首页 > 其它

UVa 11300 Spreading the Wealth (数学推导-中位数)

2016-12-07 21:53 417 查看

UVa 11300 Spreading the Wealth

题目大意:

n个人围成环形,一个人可以给他相邻左右两边的人金币,求使得所有人最后的金币数相同的最少转手金币数,金币总数能被n整除.

题目分析:

这是一个环形的结构,可以尝试将其变成单向的,Xi表示从i传到i+1的金币个数(Xn表示从n传到1的金币个数),设每人最终的金币个数为M,则有Ai+Xi−1−Xi=M.

设Ci=∑ni=1(Ai−M),则有

对于第1个人,A1+Xn−X1=M→X1=Xn−C1

对于第2个人,A2+X1−X2=M→X2=Xn−C2



对于第n个人,An+Xn−1−Xn=M.然而这个式子却没有用,可以由前面n-1的式子推导得到,所以需要挖掘其他的信息.

由上述推导可知

ans=min{|Xn|+|Xn−C1|+...+|Xn−Cn−1|}

实际上当Xn为C序列的中位数,有最小值.

原因在于,如果将Xn变成Xn+1,则有

ans′=ans+left−right

(left/right表示小于等于/大于Xn的C的个数),

要使ans最小,则应当使得当前小于/大于Xn相同,所以Xn为C序列中位数

代码:

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long ll;
const int maxn=1000000+10;

ll A[maxn],C[maxn];

int main()
{
int n;
while(scanf("%d",&n)==1) {
ll sum=0;
for(int i=1;i<=n;i++) scanf("%lld",&A[i]),sum+=A[i];
ll M=sum/n;
for(int i=1;i<=n;i++) C[i]=C[i-1]+M-A[i];//求出C序列的值
sort(C+1,C+n+1);
ll x=C[n>>1],ans=0;//X为排序后C数组的中间值
for(int i=1;i<=n;i++) ans+=abs(x-C[i]);
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: