分金币
题目描述
给定N个人成环状坐,每个人初始分配Ai的金币,金币总数可以被N整除,每个人可以给左右相邻的人一定数量的金币使得最终每个人的金币数量相同,求转移数量最小的方案所转移的总金币数量。
N<=1000000
有多组数据,对每组数据保证输出在long long范围之内。
样例输入
3
100
100
100
4
1
2
5
4
样例输出
0
4
分析(少打分析,今洒家也图个新鲜)
先设Xi表示第i+1个人给第i个人(第1个人给第n个人)的金币数;ave表示分完后每个人所拥有的金币数;
可以建立方程(最初信息储存在Ai中):
A1-X1+X2=ave;
A2-X2+X3=ave;
A3-X3+X4=ave;
。。。
An-1-Xn-1+Xn=ave;(An-Xn+X1=ave没用,前n-1个人分完后,最后一个肯定是ave个)
转一下:
X2=ave-A2+X1; 引入变量Ci=Ai-ave: X2=X1-C2;
。。。 。。。
Xn=ave-An-1-Xn-1; Xn=Xn-1-Cn-1=Xn-2-Cn-2-Cn-1=...;
要使X2...Xn-1最小,X1就是Ci的中位数,这样就简单了,递推一下就行了;
%I64d没改,在UVa上提交要用%lld

#include<cstdio> #include<algorithm> using namespace std; int n; long long a[1000005],c[1000005],ave,ans; int main() { while(scanf("%d",&n)==1){ ave=0; for(int i=1;i<=n;i++){scanf("%I64d",&a[i]);ave+=a[i];} ave/=n; c[0]=0; for(int i=1;i<n;i++) c[i]=c[i-1]+a[i]-ave; sort(c,c+n); ans=0;long long x1=c[n/2]; for(int i=0;i<n;i++) ans+=abs(x1-c[i]); printf("%I64d ",ans); } return 0; }