UVa 11300 Spreading the Wealth
题目大意:
n个人围成环形,一个人可以给他相邻左右两边的人金币,求使得所有人最后的金币数相同的最少转手金币数,金币总数能被n整除.
题目分析:
这是一个环形的结构,可以尝试将其变成单向的,
Xi
表示从i传到i+1的金币个数(
Xn
表示从n传到1的金币个数),设每人最终的金币个数为
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
序列的中位数,有最小值.
原因在于,如果将
ans′=ans+left−right
(left/right表示小于等于/大于 Xn 的 C 的个数),
要使ans最小,则应当使得当前小于/大于
代码:
#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;
}