zoukankan      html  css  js  c++  java
  • [bzoj1045] [HAOI2008] 糖果传递

    Description

    有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。

    Input

    第一行一个正整数nn<=1'000'000,表示小朋友的个数.

    接下来n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.

    Output

    求使所有人获得均等糖果的最小代价。

    Sample Input

    4
    1
    2
    5
    4
    

    Sample Output

    4
    

    Solution

    (x_i)表示第(i)个人给了第(i-1)个人多少,负数表示反着给,(x_1)表示(1)号给(n)号。

    (s=sum_{i=1}^{n}a_i/n),即平均数。

    所以显然可以得到一系列等式:

    [s=a_1-x_1+x_2\ s=a_2-x_2+x_3\ vdots \ s=a_n-x_n+x_1 ]

    但是注意到最后一个可以被前面的推出来,所以不能解出(x),可以考虑用(x_1)表示剩下的(x),得:

    [x_2=s-a_1+x_1\ x_3=2s-a_1-a_2+x_1\vdots\ x_n=a_n-s+x_1=(n-1)s-sum_{i=1}^{n-1}a_i+x_1 ]

    然后可以发现前面那一块可以(O(n))算出来,设为(c_i),那么问题就转化为了最小化:

    [f(x)=sum_{i=1}^{n}|c_i-x| ]

    这个可以看成一维数轴上一个点和一堆确定的点的距离和,取中点就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long 
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e6+10;
    
    int n,a[maxn],c[maxn],ans;
    
    signed main() {
    	read(n);int sum=0;
    	for(int i=1;i<=n;i++) read(a[i]),sum+=a[i];sum/=n;
    	for(int i=2;i<=n;i++) c[i]=c[i-1]+sum-a[i-1];
    	int mid=(n+1)>>1;nth_element(c+1,c+mid,c+n+1);
    	for(int i=1;i<=n;i++) ans+=abs(c[mid]-c[i]);write(ans);
    	return 0;
    }
    
  • 相关阅读:
    三步完成自适应网页设计
    EasyUI DataGrid 修改每页显示数量的最大值&&导出Grid到Excel
    EasyUI DataGrid 实用例子(2015-05-22)
    C# 如何将List拆分成多个子集合
    EasyUI Tabs绑定右键
    微信支付-扫码支付备忘
    微信支付:模板消息实现过程备忘
    4、http协议之二
    1、套按字及http基础知识之一
    3、Web server 之httpd2.2 配置说明
  • 原文地址:https://www.cnblogs.com/hbyer/p/10382952.html
Copyright © 2011-2022 走看看