bzoj1045 糖果传递
Description
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
Input
第一行一个正整数nn<=1'000'000,表示小朋友的个数.
接下来n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.
Output
求使所有人获得均等糖果的最小代价。
Sample Input
4
1
2
5
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 \times 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; }
弱者就是会被欺负呀