BZOJ1045 HAOI2008 糖果传递 其他

题意:给定一个有N个点的环,每个点上有一个数字,每次可以让一个点--然后左边或右边的点++,求最少操作次数

题解:

定义第i个熊孩子向他左边(也就是第i-1个熊孩子)传递的糖果数为Ci,根据题意最后每个熊孩子手里都有A=sum(ai)/n个糖果,因此:a1-C1+C2=a2-C2+C3=……=an-Cn+a1=A

因此C2=A+C1-a1,C3=A+C2-a2,C4=A+C2-a2……Cn=A+Cn-1-an-1。(C可以是负数,这样就是i-1向i传递糖果)

A固定,ai固定,因此让sum(Ci)尽可能的小,定义Di=ai-Ci,那么Ci=A-Di-1。由于A固定,并且Ci都可以表示为C1-Di-1,因此就是找到一个数M,使得sum(|Ci-M|)最小。

可以将C1到Cn按顺序放到数轴上,那么就是找到一个点,使得这个点到其他点的距离和最小。假定C已经有序,那么到C1和Cn距离最小的点是两者之间的任一点,到C2和Cn-1距离最小的点是两者间任一点……一层一层的往里走,就会发现到每个点距离和最小的点就是这些数的中位数。因此M=Cn/2+1。(如果是偶数,那么点一定落在Cn/2和Cn/2+1上,由于无论在这两个点的哪个点,距离和都相同)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;

int n,a[1000001],c[1000001],ave;
long long sum,ans;
int main(){
    scanf("%d",&n);

    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    ave=sum/n;

    for(int i=2;i<=n;i++) c[i]=c[i-1]+a[i]-ave;

    sort(c+1,c+n+1);

    int mid=c[(n>>1)+1];
    for(int i=1;i<=n;i++) ans+=abs(c[i]-mid);

    printf("%lld",ans);
    return 0;
}
View Code

 

posted @ 2017-02-28 01:56  WDZRMPCBIT  阅读(190)  评论(0编辑  收藏  举报