【中位數】BZOJ1045(HAOI2008)[糖果傳遞]題解
阿新 • • 發佈:2018-12-31
題目概述
有 個JZ坐成一圈,每人有 個神犇值。每人只能給左右兩人傳遞神犇值。每人每次傳遞一個神犇值代價為 。用最少的代價使 個JZ神犇值一樣,以便虐人。
解題報告
遠古省選題……被各種改題意,貌似已經爛大街了?
假設第 個人向 傳遞了 (負數表示 向 傳遞),令 ,那麼:
令 ,累加後得到:
也就是說答案轉化到了一個變數身上,這就比較好處理了。觀察這個式子,我們可以認為這是 與 的距離之和,最小值在 在 的中位數取到。
示例程式
#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;
}