zoukankan      html  css  js  c++  java
  • BZOJ1045 HAOI2008糖果传递(贪心)

      显然最后每个小朋友所拥有的糖果数就是糖果数总和的平均数。设该平均数为t。

      环的问题一般断成链,但这个题似乎没有什么很好的办法在枚举断点的时候快速算出答案(我甚至不知道会不会有断点)

      于是我们假装把他断开了。假装现在我们已经知道了1号小朋友要给n号小朋友x颗糖果(可以为负)。那么,2给1,3给2,4给3,等等等等,小朋友之间传递的糖果数都被确定了。

      1号给了n号x颗后,其还剩a1-x颗,那么2号小朋友就要给1号t-(a1-x)=x-(a1-t)颗。

      把1、2号看成整体,给了n号x颗后,其还剩a1+a2-x颗,那么3号小朋友就要给他们x-[(a1+a2)-t*2]颗。

      以此类推,k号小朋友要给k-1号x-[(a1+a2+……+ak-1)-t*(k-1)]颗。

      我们的目标是使上面所有数的绝对值之和最小。与这个值有关的量里只剩x是变量了。

      那么什么时候这个值最小?假装这有一个数轴,有一些点是0,a1-t(a1+a2)-t*2,等等等等。

      我们要找一个点x使得其到这些点的距离之和最小。显然放在最中间,也就是中位数的位置就行了。

      stl里有个nth_element的黑科技,线性找第k大。

    // luogu-judger-enable-o2
    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 1000010
    int n;
    long long a[N],s[N],k,ans=0;
    int main()
    {
        n=read();
        for (int i=1;i<=n;i++) s[i]=s[i-1]+read();
        k=s[n]/n;
        for (int i=1;i<=n;i++) a[i]=s[i-1]-k*(i-1);
        nth_element(a+1,a+(n+1>>1),a+n+1);
        for (int i=1;i<=n;i++) ans+=abs(a[i]-a[n+1>>1]);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    左滑删除 --- 自定义组件(优化)
    扩展方法
    关于Windows服务中的一点小记录
    MySQL数据库方面
    反射初探
    FireDAC读取数据Delphi
    Delphi学习之 FireDAC
    向ComboBox列表框中添加Enum的全部数据
    怎样在VC中生成一个DLL
    AutoCAD 开发备注
  • 原文地址:https://www.cnblogs.com/Gloid/p/9404104.html
Copyright © 2011-2022 走看看