BZOJ3293:[CQOI2011]分金币
Description
圆桌上坐着n个人,每人有一定数量的金币,金币总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数目相等。你的任务是求出被转手的金币数量的最小值。
Input
第一行为整数n(n>=3),以下n行每行一个正整数,按逆时针顺序给出每个人拥有的金币数。
Output
输出被转手金币数量的最小值。
Sample Input
4
1
2
5
4
1
2
5
4
Sample Output
4
样例解释
设四个人编号为1,2,3,4。第3个人给第2个人2个金币(变成1,4,3,4),第2个人和第4个人分别给第1个人1个金币。
样例解释
设四个人编号为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("\n") 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!='\n' 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