1. 程式人生 > >P2512 [HAOI2008]糖果傳遞 題解 數學

P2512 [HAOI2008]糖果傳遞 題解 數學

put sam spa clr div -c scanf bad img

  

題目描述

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

輸入輸出格式

輸入格式:

小朋友個數n 下面n行 ai

輸出格式:

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

輸入輸出樣例

輸入樣例#1: 復制
4
1
2
5
4
輸出樣例#1: 復制
4

首先,最終每個小朋友的糖果數量可以計算出來,等於糖果總數除以n,用ave表示。

假設標號為i的小朋友開始有Ai顆糖果,Xi表示第i個小朋友給了第i-1個小朋友Xi顆糖果,如果Xi<0,說明第i-1個小朋友給了第i個小朋友Xi顆糖果,X1表示第一個小朋友給第n個小朋友的糖果數量。 所以最後的答案就是ans=|X1| + |X2| + |X3| + ……+ |Xn|。 對於第一個小朋友,他給了第n個小朋友X1顆糖果,還剩A1-X1顆糖果;但因為第2個小朋友給了他X2顆糖果,所以最後還剩A1-X1+X2顆糖果。根據題意,最後的糖果數量等於ave,即得到了一個方程:A1-X1+X2=ave。

同理,對於第2個小朋友,有A2-X2+X3=ave。最終,我們可以得到n個方程,一共有n個變量,但是因為從前n-1個方程可以推導出最後一個方程,所以實際上只有n-1個方程是有用的。

盡管無法直接解出答案,但可以用X1表示出其他的Xi,那麽本題就變成了單變量的極值問題。

對於第1個小朋友,A1-X1+X2=ave -> X2=ave-A1+X1 = X1-C1(假設C1=A1-ave,下面類似)

對於第2個小朋友,A2-X2+X3=ave -> X3=ave-A2+X2=2ave-A1-A2+X1=X1-C2

對於第3個小朋友,A3-X3+X4=ave -> X4=ave-A3+X3=3ave-A1-A2-A3+X1=X1-C3

…… 對於第n個小朋友,An-Xn+X1=ave。

我們希望Xi的絕對值之和盡量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要盡量小。註意到|X1-Ci|的幾何意義是數軸上的點X1到Ci的距離,所以問題變成了:給定數軸上的n個點,找出一個到他們的距離之和盡量小的點,而這個點就是這些數中的中位數,證明略。

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define
repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define pb push_back #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 0x3f3f3f3f #define lson l,m,pos<<1 #define rson m+1,r,pos<<1|1 const int N=1e6+5; int a[N],b[N]; int main() { int n;RI(n); ll sum=0; rep(i,1,n) RI(a[i]),sum+=a[i]; sum/=n; rep(i,1,n) b[i]=b[i-1]-a[i]+sum; sort(b+1,b+1+n); ll mid=b[(n+1)/2]; ll ans=0; rep(i,1,n)ans+=abs(b[i]-mid); cout<<ans; return 0; }
View Code

P2512 [HAOI2008]糖果傳遞 題解 數學