• [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;
    }
    
  • 相关阅读:
    Java 常见异常种类
    Spring3.2+mybatis3.2+Struts2.3整合配置文件大全
    Java中的基本类型和引用类型变量的区别
    【git】Git 提示fatal: remote origin already exists 错误解决办法
    【Java集合】Java中集合(List,Set,Map)
    POJ3322-经典的游戏搜索问题
    程序人生[流程图]
    不使用中间变量交换两个数
    做人要低调,别把自己太当回事
    【转】嵌套子控件设计时支持
  • 原文地址:https://www.cnblogs.com/hbyer/p/10382952.html
Copyright © 2020-2023  润新知