1432:糖果傳遞
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 999 通過數: 452
【題目描述】
有n個小朋友坐成一圈,每人有ai個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞一個糖果代價爲1。
【輸入】
第一行一個正整數n≤1000000,表示小朋友的個數.
接下來n行,每行一個整數ai,表示第i個小朋友得到的糖果的顆數.
【輸出】
求使所有人獲得均等糖果的最小代價。
【輸入樣例】
4
1
2
5
4
【輸出樣例】
4
思路:
最終每個小朋友的糖果數等於平均數,假設編號爲i的小朋友開始有Ai個糖果。Xi表示第i個小朋友給了第i-1個小朋友Xi個糖果,Xi<0表示第i-1個小朋友給了第i個小朋友|Xi|個糖果。則最終的答案ans=|X1|+|X2|+……+|Xn|。
對於第一個小朋友,他給了第n個小朋友X1個糖果,得到第2個小朋友的X2個糖果,最終還剩A1-X1+X2個糖果,即ave個糖果,所以得到方程A1-X1+X2=ave。所以ans=|X1|+|X1-C1|+|X1-C2|+…+|X1-Cn-1|,要使ans儘可能小。因爲|X1-Ci|的幾何意義是數軸上點X1到Ci的距離,所以問題轉化爲:給定數軸上n個點,找出一個點到各點距離和最小。所以這個點就是中位數。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
const int N=1000005;
int n,ave;
int a[N],f[N];
LL sum,ans;
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
sum += a[i];
}
ave=sum/n; //最終小朋友手裏的糖數
for(int i = 2;i <= n;i++)f[i] = f[i-1] + a[i-1]-ave; //左邊的小朋友傳給右邊
sort(f+1,f+n+1);
int mid = n/2+1;//傳遞的中位數
for(int i=1;i<=n;i++)
for(int i = 1;i <= n;i++){
ans += abs(f[i]-f[mid]);//只需要傳遞到中位數就好了,多了太浪費
}
printf("%lld\n",ans);
return 0;
}