bzoj 1045 中位数+数学推导

Description

  有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。

Input

  第一行一个正整数n<=987654321,表示小朋友的个数.接下来n行,每行一个整数ai,表示第i个小朋友得到的
糖果的颗数.

Output

  求使所有人获得均等糖果的最小代价。

Sample Input

4
1
2
5
4

Sample Output

4

我们令 ave = segma(ai)  / n  (1<=i<=n)

一个小盆友向左右两人都可传递糖果,是双向的,我们就可以用正负来表示方向~,这样我们就可以变成“单向”的形式

我们设第i个小盆友向第i-1个小盆友传递了xi个糖果(xi为正,表示第i个小盆友给第i-1个小盆友糖果,i为负表示第i-1个小盆友给第i个小盆友糖果~)

那么,ans=|x1|+|x2|+...+|xn| (注意是绝对值的和

那么对于每一个小盆友我们有ai-xi+xi+1=ave

我们可以得到n个这样的方程,但是我们是无法直接解出答案的_(:з」∠)_

由于是最值问题,我们考虑单变量的最值问题,我们尝试用x1表示其他的xi

a1-x1+x2=ave  -> x2=ave-a1+x1

a2-x2+x3=ave  -> x3=ave-a2+x2=ave-a2+ave-a1+x1

......

an-xn+x1=ave -> xn=segma(ave-ai)+x1 (1<=i<=n-1)

由于ave 与 ai 为常数,所以我们用ci表示

即c1=ave-a1,c2=ave-a2+ave-a1, ...,cn=segma(ave-ai) (1<=i<=n-1)

那么,ans=|x1|+|x2|+..+|xn|=|x1|+ |c1+x1| + |c2+x1| +...+| cn+x1|

因为 |ci+x1|=|ci-(-x1)|

所以 ans=|x1|+|c2-(-x1)|+...+|cn-(-x1)|

此时,我们很容易想到中位数的一个性质:

有一列数X1,X2,X3,...,Xn,

f(x)=|X1-x|+|X2-x|+|X3-x|+...+|Xn-x|,当x=数列中位数时,f(x)最小

所以,当-x1=c数组组成的数列的中位数时,ans最小

================我是理想与现实的分界线_(:з」∠)_ ================

所以我们在计算ci的时候直接取负就好了

即:c1 = a1-ave , c2 = a2-ave + a1-ave , ... ,  cn=segma(ai-ave) (1<=i<=n-1)

所以 x2 = c1-x1 ,  x3 = c2-x1,... ,xn = cn-x1

我们令x1=c数组的中位数 算出 ans=|x1|+|c1-x1|+|c2-x1|+....+|cn-x1| 即可

var
        n,median,ave    :longint;
        sum,ans         :int64;
        a,c             :array[0..1000010] of longint;
        i               :longint;
procedure sort(l,r: longint);
var
         i,j,x,y: longint;
begin
         i:=l;
         j:=r;
         x:=c[(l+r) div 2];
         repeat
           while c[i]<x do inc(i);
           while x<c[j] do dec(j);
           if not(i>j) then
             begin
                y:=c[i];c[i]:=c[j];c[j]:=y;
                inc(i);j:=j-1;
             end;
         until i>j;
         if l<j then sort(l,j);
         if i<r then sort(i,r);
end;

begin
   read(n);sum:=0;
   for i:=1 to n do read(a[i]);
   for i:=1 to n do inc(sum,a[i]);
   ave:=sum div n;
   c[1]:=0;
   for i:=2 to n do c[i]:=a[i]-ave+c[i-1];
   sort(1,n);
   ans:=0;
   if (n mod 2=1) then median:=c[n div 2+1]
    else median:=(c[n div 2]+c[n div 2+1]) div 2; 
   for i:=1 to n do inc(ans,abs(median-c[i]));
   writeln(ans);
end.
—— by Eirlys



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值