BZOJ3293:[CQOI2011]分金币

Description

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

Input

第一行为整数nn>=3),以下n行每行一个正整数,按逆时针顺序给出每个人拥有的金币数。

Output

输出被转手金币数量的最小值。

Sample Input

4
1
2
5
4

Sample Output

4
样例解释
设四个人编号为1,2,3,4。第3个人给第2个人2个金币(变成1,4,3,4),第2个人和第4个人分别给第1个人1个金币。

HINT

N<=100000,总金币数<=10^9

题解:

一道很经典的题目。

用b[i]表示前i个人总共还需要多少金币(即第n人与第1人、第i人与下一个的金币交换情况)。

设第n个人给了第1个人x金币,则第i个人与下一个人的金币流动量为|b[i]-x|。

我们要使∑|b[i]-x|最小,则x应选b的中位数。

代码(P++注意):

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define begin {
 4 #define end }
 5 #define while while(
 6 #define if if(
 7 #define do )
 8 #define then )
 9 #define for for(
10 #define fillchar(a,b,c) memset(a,c,b)
11 #define writeln printf("
")
12 #define write printf
13 #define readln readl()
14 #define inc(a) a++
15 #define dec(a) a--
16 #define exit(a) return a
17 #define mod %
18 #define div /
19 #define shl <<
20 #define shr >>
21 #define extended long double
22 #define longint int
23 #define integer short
24 #define int64 long long
25 template<typename T> inline void read(T& a)
26 begin
27   T x=0,f=1; char ch=getchar();
28   while(ch<'0')or(ch>'9')do
29   begin
30     if ch=='-' then f=-1; ch=getchar();
31   end
32   while(ch>='0')and(ch<='9')do
33   begin
34     x=x*10+ch-'0'; ch=getchar();
35   end
36   a=x*f;
37 end
38 inline void readl()
39 begin
40   char ch; ch=getchar();
41   while ch!='
' do ch=getchar();
42 end
43 int64 a[100001],b[100001];
44 int64 tot,n,m,i;
45 int64 ans;
46 int main()
47 begin
48   read(n);
49   for i=1;i<=n;i++ do begin read(a[i]); tot=tot+a[i]; end;
50   tot=tot div n;
51   for i=1;i<=n;i++ do b[i]=b[i-1]+tot-a[i];
52   sort(b+1,b+n+1); tot=b[(1+n)div 2];
53   for i=1;i<=n;i++ do ans=ans+abs(tot-b[i]);
54   write("%lld",ans); writeln;
55 end
View Code
原文地址:https://www.cnblogs.com/GhostReach/p/6398346.html