码迷,mamicode.com
首页 > 其他好文 > 详细

P2512 [HAOI2008]糖果传递&&P3156 [CQOI2011]分金币&&P4016 负载平衡问题

时间:2018-09-01 20:24:35      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:前缀和   etc   最小   糖果   ++   ring   amp   ...   pre   

P2512 [HAOI2008]糖果传递

第一步,当然是把数据减去平均数,然后我们可以得出一串正负不等的数列

我们用sum数组存该数列的前缀和。注意sum[ n ]=0

假设为链,那么可以得出答案为abs( sum[ 1 ] )+abs( sum[ 2 ] )+...+abs( sum[ n ] )

但是题目说的是环

我们设在第 k 个人处断开环成链。 那么答案为
abs( sum[ k+1 ] - sum[ k ] )+abs( sum[ k+2 ] - sum[ k ] )+...+abs( sum[ n ] - sum[ k ] )+abs( sum[ n ] - sum[ k ] + sum[ 1 ])+abs( sum[ n ] - sum[ k ] + sum[ 2 ])+...+abs( sum[ n ] - sum[ k ] + sum[ k ])

代入sum[ n ]=0后,得abs( sum[ k+1 ] - sum[ k ] )+abs( sum[ k+2 ] - sum[ k ] )+...+abs( sum[ n ] - sum[ k ] )+abs( sum[ 1 ] - sum[ k ] )+abs( sum[ 2 ] - sum[ k ] )+...+abs( sum[ k ] - sum[ k ] )

=abs( sum[1~n] - sum[k] )

我们把 sum[1~n] 扔到数轴上,发现问题变成:找出一个点,使它到其他点的距离最小。显然这个点是中位数。

end.

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll Get(){
    char c=getchar(); ll x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x;
}
ll ans,a[1000002],sum[1000002]; int n;
int main(){
    scanf("%d",&n);
    ll tot=0;
    for(int i=1;i<=n;++i) a[i]=Get(),tot+=a[i];
    tot/=n;
    for(int i=1;i<=n;++i) a[i]-=tot,sum[i]=a[i]+sum[i-1]; //减平均数,求前缀和
    sort(sum+1,sum+n+1);
    ll mid=sum[(n+1)>>1]; //排序后找中位数
    for(int i=1;i<=n;++i) ans+=abs(sum[i]-mid);
    printf("%lld",ans);
    return 0;
}

P2512 [HAOI2008]糖果传递&&P3156 [CQOI2011]分金币&&P4016 负载平衡问题

标签:前缀和   etc   最小   糖果   ++   ring   amp   ...   pre   

原文地址:https://www.cnblogs.com/kafuuchino/p/9571297.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!