1. 程式人生 > >【中位數】BZOJ1045(HAOI2008)[糖果傳遞]題解

【中位數】BZOJ1045(HAOI2008)[糖果傳遞]題解

題目概述

n 個JZ坐成一圈,每人有 ai 個神犇值。每人只能給左右兩人傳遞神犇值。每人每次傳遞一個神犇值代價為 1 。用最少的代價使 n 個JZ神犇值一樣,以便虐人。

解題報告

遠古省選題……被各種改題意,貌似已經爛大街了?

假設第 i 個人向 i+1 傳遞了 xi (負數表示 i+1i 傳遞),令 ave=i=1nain ,那麼:

xnx1=avea1x1x2=avea2xn1xn=avean
ci=i=1naveai ,累加後得到:
xnx1=c1xnx2=c2xnxn=cnans=i=1n|xi|=i=1n|xnci|
也就是說答案轉化到了一個變數身上,這就比較好處理了。觀察這個式子,我們可以認為這是 xnci 的距離之和,最小值在 xn{cn} 的中位數取到。

示例程式

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std; typedef long long LL; const int maxn=1000000; int n,a[maxn+5];LL ave,sum[maxn+5],ans; #define Eoln(x) ((x)==10||(x)==13||(x)==EOF) inline char readc(){ static char buf[100000],*l=buf,*r=buf; if (l==r) r=(l=buf)+fread(buf,1,100000,stdin); if (l==r) return EOF;return *l++; } inline int
readi(int &x){ int tot=0,f=1;char ch=readc(),lst='+'; while (!isdigit(ch)) {if (ch==EOF) return EOF;lst=ch;ch=readc();} if (lst=='-') f=-f; while (isdigit(ch)) tot=(tot<<3)+(tot<<1)+(ch^48),ch=readc(); return x=tot*f,Eoln(ch); } inline LL Abs(LL x) {if (x<0) return -x;return x;} int main(){ freopen("program.in","r",stdin); freopen("program.out","w",stdout); readi(n);for (int i=1;i<=n;i++) readi(a[i]),ave+=a[i]; ave/=n;for (int i=1;i<=n;i++) sum[i]=sum[i-1]+ave-a[i]; sort(sum+1,sum+1+n);LL mid=sum[n+1>>1]; for (int i=1;i<=n;i++) ans+=Abs(sum[i]-mid); return printf("%lld\n",ans),0; }