【BZOJ1045】糖果传递

题目

有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。求使所有人获得均等糖果的最小代价。

分析

又是以前弄懂了,第二次做又不会了,下面自己手打一遍数学证明吧

设 give[i]为第i个人给第i-1个人的糖果数量,a[i]为本身的糖果数量

设均等的糖果数为 ave=sum/n

则 a[1]+give[2]-give[1]=ave

a[2]+give[3]-give[2]=ave

·········

移项

give[2]=give[1]+ave-a[1]

give[3]=give[2]+ave-a[2]=give[1]+ave-a[1]+ave-a[2]

可以观察到有一个 ave-a[i]的部分

设b[i]=a[i]-ave 再设c[i]为b数组的前缀和

则有 give[i]=give[1]-c[i-1]

give[1]+give[2]+·······+give[n]=| c[0]-give[1] |+| c[1]-give[1] |+······+| c[n-1]-give[1] |

相当于求数轴上的n个点到一定点的距离和的最小值

就是初一数学学的, 所以give[1]取序列c的中位数即可

代码

#include<bits/stdc++.h>
using namespace std;
#define N 1001000
#define ll long long
ll n,sum,aver,minx,ans;
ll a[N],c[N];
inline void read(ll &x)
{
    x=0;char ch=getchar();
    while(ch>'9'||ch<'0'){ch=getchar();}
    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++)
        read(a[i]),sum+=a[i];
    aver=sum/n;
    for(int i=1;i<=n;i++)
        c[i]=c[i-1]-aver+a[i];
    sort(c+1,c+1+n);
    minx=c[(n+1)>>1];
    for(int i=1;i<=n;i++)
        ans+=abs(c[i]-minx);
    printf("%lld
",ans);
    return 0;
}
“Make my parents proud,and impress the girl I like.”
原文地址:https://www.cnblogs.com/NSD-email0820/p/9637694.html