分金币
题目描述:
圆桌旁坐着n个人,每人有一定数量的金币,金币总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数相等。你的任务是求出被转手的金币数量的最小值。比如,n=4,且4个人的金币数分别为1,2,5,4时,只需转移4枚金币(第3个人给第2个人两枚金币,第2个人和第4个人分别给第1 个人1枚金币)即可实现每人手中的金币数目相等。
Input:
输入包含多组数据。每组数据第一行为整数n(n<=1 000 000),以下n行每行为一个整数,按逆时针顺序给出每个人拥有的金币数。输入结束标志为文件结束符(EOF)。
Output:
对于每组数据,输出被转手金币数量的最小值。输入保证这个值在64位无符号整数范围内。
Sample Input:
4 1 2 5 4
Sample Output:
4
题解:
假设M为每个人都拥有的金币数,每个人的金币变化是左右相邻的人对其造成的影响
假设这n个人构成一个环,先假设n=4,设(x1)指1号给4号多少金币,则(x2)代表2号给1号
多少金币,其他的由此类推下去。
则对于1号来说,他给了4号金币,则剩(a1-x1)
2号给了他金币,则剩(a1-x1+x2)
注意这里1号给4号和4号给1号的意义隐含在x1的符号里面(很巧妙),其他的类似
由于最后要等于M,然后就可以得方程了
(a1-x1+x2=M >> x2 = x1-(a1-M) = x1 - C1\
a2-x2+x3=M >> x3 = x2-(a2-M)=x1-a1-a2-2*M = x1 - C2\
a3-x3+x4=M >> x4 = x3-a1-a2-a3-3*M = x1 - C3\
an-xn+x1=M >> xn = x1 - C(n-1))
看到这里我们知道答案是所有xi的绝对值最小了
很显然这就转化为数轴上求一点x到(ci)距离和的最小值,然而这个点x其实就是序列(ci)(排
序后)的中位数,稍微想想应该知道
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1000000+10;
long long A[maxn], C[maxn], tot, M;
int main(){
int n;
long long sum = 0;
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf("%d", &A[i]);
sum += A[i];
}
int arg = sum/n;
C[0] = 0;
for(int i = 1; i < n; ++i){
C[i] = C[i-1] + A[i] - arg;
}
sort(C, C+n);
long long x1 = C[n/2];
long long ans = 0;
for(int i = 0; i < n; ++i){
ans += abs(x1 - C[i]);
}
printf("%lld
", ans);
return 0;
}
结论:
给定数轴上的n个点,在数轴上的所有点中,中位数离所有顶点的距离之和最小。