1. 程式人生 > >BZOJ-1045-[HAOI2008] 糖果傳遞(中位數原理)

BZOJ-1045-[HAOI2008] 糖果傳遞(中位數原理)

event esc 原理 its 表示 style sed src 推出

Description

有n個小朋友坐成一圈,每人有ai個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞一個糖果代價為1。

Input

第一行一個正整數nn<=1‘000‘000,表示小朋友的個數. 接下來n行,每行一個整數ai,表示第i個小朋友得到的糖果的顆數.

Output

求使所有人獲得均等糖果的最小代價。

Sample Input

4
1
2
5
4

Sample Output

4

題解

這道題對於最終小朋友手中的糖的數量我們是可以算出來的,我們用ave來表示

我們假設Gi表示第i個人給第i-1個人糖的數量,G1表示第1個人給第n個人

那麽最後答案就是|G1|+|G2|+···+|Gn|

那麽到最後

第一個人的糖就是A1-G1+G2=ave

第二個人的糖就是A2-G2+G3=ave

······

第n個人的糖就是An-Gn+G1=ave

這裏我們假設Ci=Ci-1+Ai-ave

所以通過第一個人的糖,我們可以推出G2=G1-C1

通過第二個人,可以推出G3=G1-C2

······

第n個人,可以推出Gn

=G1-Cn-1

所以最後答案就變成了|G1|+|G1-C1|+|G1-C2|+···+|G1-Cn-1|

對於求最後答案,問題就變成了給你坐標軸上的n個點,要你找到一個點,使得這個點到所有的點的距離之和最小

而這個點的坐標就是坐標軸上點的中位數

技術分享
 1 #include<bits/stdc++.h>
 2 #define N 1000005
 3 #define ll long long
 4 using namespace std;
 5 int n,ave;
 6 ll sum,ans;
 7 int a[N],c[N];
8 int main(){ 9 scanf("%d",&n); 10 for (int i=1;i<=n;i++){ 11 scanf("%d",&a[i]); 12 sum+=a[i]; 13 } 14 ave=sum/n; 15 for (int i=2;i<=n;i++) 16 c[i]=c[i-1]+a[i]-ave; 17 sort(c+1,c+1+n); 18 int mid=c[(n>>1)+1]; 19 for (int i=1;i<=n;i++) 20 ans+=abs(mid-c[i]); 21 printf("%lld\n",ans); 22 return 0; 23 }
View Code

BZOJ-1045-[HAOI2008] 糖果傳遞(中位數原理)