[HAOI2008]糖果传递
[HAOI2008]糖果传递
Description
有\(n\)个小朋友坐成一圈,每人有\(a_i\)个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为\(1\)。
Input
第一行一个正整数\(n<=1000000\),表示小朋友的个数.
接下来\(n\)行,每行一个整数\(a_i\),表示第i个小朋友得到的糖果的颗数.
Output
求使所有人获得均等糖果的最小代价。
Sample Input
4
1
2
5
4
Sample Output
4
环形均分纸牌
本来以为均分纸牌很简单,才发现很多东西理解不到位,这里直接转载大佬的题解啦。
原题解戳这里
首先这道题是一个模型,我们称之为环形均分纸牌。显然这个模型是出自luogu1031那道均分纸牌,没有过的可以先过一下。
先来看不是环形的情况。
假设总和为 \(T\) ,有 \(M\) 张纸牌。设 \(ave = \dfrac{T}{M}\) 。对于第\(i\)个人来说,如果 \(C[i] < ave\) 他拿的应该是 \(C[i] + ave\) 张,后一个拿 \(C[i + 1] - ave + C[i]\) ,否则,他拿 \(C[i] - ave\) 张,而后一个拿 \(C[i + 1] + C[i] - ave\) 张。
但是这样并不方便维护,我们考虑整体和隔离的思想。将前\(i\)个看做一个整体,显然前\(i\)个内部的均分是不会改变其整体结构的,因而对于该体系来说,想要达到平均数结构,就必须与下一个体系交换足够的纸牌,而交换数量就是 \(|G[i] - i \cdot ave|\) ,其中 \(G[i]\) 是前缀和。然后就可以推出一个结论: \(d = \sum ^M _{i = 1} |i \cdot ave - G[i]|\),也就是将每次体系更新的贡献加起来。
如果让每个人的数量都减去 \(ave\) ,结果就可以经过简单的数学推导进一步化简: \(d = \sum ^M _{i = 1} |S[i]|\) ,其中 \(S[i]\) 是新数组的前缀和。这就是均分纸牌问题的通用公式。
现在考虑一种变形:如果这里的纸牌是环形的呢?
对于环形问题,首先考虑切开。假定我们切开的东西是 \(A[k + 1], A[k + 2], ..., A[M], A[1], ..., A[k]\) ,那么其前缀和也会有所变化,即 \(S[k + 1] - S[k], S[k + 2] - S[k], ..., S[M] - S[k], .S[1] + S[M] - S[k], ..., S[M]\)
由于均分之后, \(S[M] = 0\)恒成立,所以前缀和的变化仅仅是减去 \(S[k]\) 。那么,我们要求的就是哪个取值上最短,换言之,求什么时候 \(\sum^M_{i = 1} |S[i] - S[k]|\) 取到最小。
因而,这里我们要求的东西是 \(\sum^M_{i = 1} |S[i] - S[k]|\) 的最小值。答案是在中位数处取到,原因各位可以想象将 \(S[i]\) 投影到一个坐标平面内。然后我们用一条线去扫,点到线的距离之和就是上面的式子的最小值。从中位数的位置变化到靠下的位置或是靠上的位置,都会使某一部分点的距离增大。所以这里转化为求中位数,也就是求第 \(\dfrac{n + 1}{2}\) 大元素,由于 \(N \leq 10^6\) 所以不建议排序(虽然也能用)。我们可以用\(STL\)的nth_elements()函数\(O(n)\)求出\(k\)大。
讲的已经很清楚了,直接看代码吧
#include<bits/stdc++.h>
#define lll long long
using namespace std;
lll read()
{
lll x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
lll n,ave,qwe,ans;
lll a[1000010],sum[1000010];
int main()
{
n=read();
for(lll i=1;i<=n;i++)a[i]=read(),qwe+=a[i];
lll ave=qwe/n;
for(int i=1;i<=n;i++) a[i]-=ave,sum[i]=sum[i-1]+a[i];
sort(sum+1,sum+1+n);int cut=sum[(n+1)/2];
for(int i=1;i<=n;i++) ans+=abs(sum[i]-cut);
cout<<ans<<endl;
}