首页 > 代码库 > bzoj3293[Cqoi2011]分金币

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

 

 

可以发现只要确定了n给1的金币数,就可以确定所有人之间给的金币数,设n给1的金币数为x,写出总金币数关于x的函数,是一个绝对值函数,有几何意义,一个是一个初中就会的简单求最值,取中位数作为x就是最小值。

 1 program coin(input,output);
 2 var
 3   a,b:array[0..100010]of int64;
 4   n,i:longint;
 5   c,t,ans:int64;
 6 procedure sort(q,h:longint);
 7 var
 8   i,j:longint;
 9   x,t:int64;
10 begin
11    i:=q;j:=h;x:=b[(i+j)>>1];
12    repeat
13      while b[i]<x do inc(i);
14      while x<b[j] do dec(j);
15      if i<=j then
16         begin
17            t:=b[i];b[i]:=b[j];b[j]:=t;
18            inc(i);dec(j);
19         end;
20    until i>j;
21    if j>q then sort(q,j);
22    if i<h then sort(i,h);
23 end;
24 begin
25    assign(input,coin.in);assign(output,coin.out);reset(input);rewrite(output);
26    readln(n);
27    c:=0;
28    for i:=1 to n do begin readln(a[i]);c:=c+a[i]; end;
29    c:=c div n;
30    b[1]:=0;
31    for i:=2 to n do b[i]:=b[i-1]+c-a[i-1];
32    sort(1,n);
33    t:=b[(1+n)>>1];ans:=0;
34    for i:=1 to n do ans:=ans+abs(t-b[i]);
35    write(ans);
36    close(input);close(output);
37 end.

 

bzoj3293[Cqoi2011]分金币