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


    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;
    }
    
  • 相关阅读:
    bzoj1202 狡猾的商人
    bzoj1059 矩阵游戏
    bzoj1003 物流运输
    bzoj1601 灌水
    2017-10-25模拟赛
    洛谷—— P1051 谁拿了最多奖学金
    BZOJ——1611: [Usaco2008 Feb]Meteor Shower流星雨
    2017-10-23学大伟业Day1
    BZOJ——1610: [Usaco2008 Feb]Line连线游戏
    Vijos 包裹快递(二分)
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9571297.html
Copyright © 2020-2023  润新知