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

    Description

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

    Input

    第一行一个正整数nn<=1'000'000,表示小朋友的个数.
    接下来n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.

    Output

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

    Sample Input

    4
    1
    2
    5
    4

    Sample Output

    4
     
    这道题让我想到了白书上面的相似的一道题:

    UVA11300 Spreading the Wealth

    A Communist regime is trying to redistribute wealth in a village. They have have decided to sit everyone around a circular table. First, everyone has converted all of their properties to coins of equal value, such that the total number of coins is divisible by the number of people in the village. Finally, each person gives a number of coins to the person on his right and a number coins to the person on his left, such that in the end, everyone has the same number of coins. Given the number of coins of each person, compute the minimum number of coins that must be transferred using this method so that everyone has the same number of coins.

    Input

    There is a number of inputs. Each input begins with n (n < 1000001), the number of people in the village. n lines follow, giving the number of coins of each person in the village, in counterclockwise order around the table. The total number of coins will fit inside an unsigned 64 bit integer.

    Output

    For each input, output the minimum number of coins that must be transferred on a single line.

    Sample Input

    3
    100
    100
    100
    4
    1
    2
    5
    4

    Sample Output

    0
    4
    题意:n个人围成一圈,每个人都有一些硬币,,每个人只能给左右相邻的人硬币,问最少交换几个硬币,使每个人硬币一样多。
     
    我第一反应:费用流。第二反应:费用流。第三反应:费用流。
    然后看uva11300题解:
    首先,最终每个人金币数量可以计算出来,我们用M表示每个人最后拥有的金币数。
    我们对于第i个人可以看作他给了他左边的人xi个金币(负数表示反向传递),他右边的人给了他xi+1个金币,假设他一开始拥有的金币数量为Ai,那么有Ai-xi+xi+1=M。
    如果我们继续列下去就会变成这样:
    A1-x1+x2=M -> x2=M-A1+x1 ->  令C1=A1-M -> x2=x1-C1
    A2-x2+x3=M -> x3=M-A2+x2=2*M-A1-A2+x1 ->  令C2=A1+A2-2*M -> x3=x1-C2
    A3-x3+x4=M -> x4=M-A3+x3=3*M-A1-A2-A3+x1 ->  令C3=A1+A2+A3-3*M -> x4=x1-C3
    .......
    那么我们就会得到n个等式,但是我们发现我们可以用这n个等式中的任意n-1个去变换得到最后剩下那个等式。
    因为我们知道 $sum A_i =M imes n $ ,那么最后一个等式Cn=0,就是x1=x1
    也就是说,最后那个等式是没有用的,我们只会用到n-1个等式。那么这n-1个等式可以用来做什么呢,我们怎样才能求得 $ sum abs(x_i) $ 最小值呢?
    $ sum abs( x_i ) = abs( x_1 )+abs( x_2 )+abs( x_3 )+......+abs( x_n )=abs( x_1 ) +abs(x_1-C_1) +abs(x_1- C_2)+ ......+abs(x_1-C_{n-1})$
    由于Ci是可以直接计算出来的,可以当作常数,所以说这个等式相当于是求一个最优的x1,使得数轴上x1到Ci距离和最小,而这个距离和就是我们所求的答案。
    最后问题转化成求数轴上一个点到所有已知的点最小距离,相信在小学(或是初中)数学老师都讲过,这样的点就是中位数啦。
    然后就直接算出C,然后算中位数与其他的所有的点的距离。
     
    bzoj1045 代码:
    //Serene
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int maxn=1e6+10;
    long long n,tot,ans,c,A[maxn],C[maxn];
    
    long long aa;char cc;
    long long read() {
    	aa=0;cc=getchar();
    	while(cc<'0'||cc>'9') cc=getchar();
    	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    	return aa;
    }
    
    int main() {
    	n=read();
    	for(int i=1;i<=n;++i) A[i]=read(),tot+=A[i];
    	tot/=n;
    	for(int i=1;i<n;++i) C[i]=A[i]-tot+C[i-1];
    	sort(C+1,C+n+1);//还有一个C[i]为0的 
    	for(int i=1;i<=n;++i) ans+=abs(C[i]-C[(n+1)>>1]);
    	printf("%lld",ans);
    	return 0;
    }
    

      

    弱者就是会被欺负呀
  • 相关阅读:
    C++11 function用法 可调用对象模板类
    2017年团体程序设计天梯赛
    CCCC 以及 hihocoder offer收割赛11 ~~~
    Wannafly Union Goodbye 2016-A//初识随机化~
    Good Bye 2016 //智商再次下线,边界爆炸.....
    连做两场goodbye2016是怎样的体验.....
    2016CCPC 合肥--最大公约数//每一年通向它的路上,多少人折戟沉沙,多少人功败垂成,有人一战成名,有人从头再来。
    2016 CCPC 合肥赛区 平行四边形//打铁记录..... 背锅还是我在行 此处@ctr 233
    补题安排及挂机....
    BZOJ3670:[NOI2014]动物园
  • 原文地址:https://www.cnblogs.com/Serene-shixinyi/p/7594077.html
Copyright © 2011-2022 走看看