题意
有 n n n 个小朋友,他们围成了一个圈,每个人有 a i a_{i} ai 个糖果。每人每次传递一个糖果代价为 1 1 1。求使所有小朋友获得均等糖果的最小代价。
思路
我们设
x
i
x_{i}
xi 为第
i
i
i 个小朋友传给第
i
+
1
i+1
i+1 个小朋友的糖果数量,
a
v
e
ave
ave 为所有小朋友的糖果的平均数。则有:
a
v
e
=
1
n
(
a
1
+
a
2
+
…
a
n
)
ave=\frac{1}{n}(a_{1}+a_{2}+…a_{n})
ave=n1(a1+a2+…an)
a
i
−
x
i
+
x
i
−
1
=
a
v
e
a_{i}-x_{i}+x_{i-1}=ave
ai−xi+xi−1=ave
我们再将第二个式子展开,即:
a
1
−
x
1
+
x
n
=
a
v
e
a_{1}-x_{1}+x_{n}=ave
a1−x1+xn=ave
a 2 − x 2 + x 1 = a v e a_{2}-x_{2}+x_{1}=ave a2−x2+x1=ave
… … …
a
n
−
x
n
+
x
n
−
1
=
a
v
e
a_{n}-x_{n}+x_{n-1}=ave
an−xn+xn−1=ave
然后再移项
x
1
=
x
n
−
(
a
v
e
−
a
1
)
x_{1}=x_{n}-(ave-a_{1})
x1=xn−(ave−a1)
x 2 = x n − ( a v e − a 2 ) x_{2}=x_{n}-(ave-a_{2}) x2=xn−(ave−a2)
… … …
x
n
=
x
n
−
1
−
(
a
v
e
−
a
n
)
x_{n}=x_{n-1}-(ave-a_{n})
xn=xn−1−(ave−an)
我们再将其逐个由之前的式子替换
x
1
=
x
n
−
(
a
v
e
−
a
1
)
x_{1}=x_{n}-(ave-a_{1})
x1=xn−(ave−a1)
x 2 = x n − ( 2 × a v e − a 1 − a 2 ) x_{2}=x_{n}-(2\times ave-a_{1}-a_{2}) x2=xn−(2×ave−a1−a2)
… … …
x
n
=
x
n
−
(
n
×
a
v
e
−
a
1
−
a
2
−
…
−
a
n
)
x_{n}=x_{n}-(n×ave−a_{1}−a_{2}−…−a_{n})
xn=xn−(n×ave−a1−a2−…−an)
因为我们要求的是传递最小的代价,即为:
∣
x
1
∣
+
∣
x
2
∣
+
…
+
∣
x
n
∣
|x_{1}|+|x_{2}|+…+|x_{n}|
∣x1∣+∣x2∣+…+∣xn∣
我们发现,可以将原来的式子带入其中,并且此式后面的常数部分我们可以整理一下用
c
i
c_{i}
ci 代替。
∣
x
n
−
(
a
v
e
−
a
1
)
∣
+
∣
x
n
−
(
2
×
a
v
e
−
a
1
−
a
2
)
∣
+
…
+
∣
x
n
−
(
n
×
a
v
e
−
a
1
−
a
2
−
…
−
a
n
)
∣
|x_{n}-(ave-a_{1})|+|x_{n}-(2\times ave-a_{1}-a_{2})|+…+|x_{n}-(n×ave−a_{1}−a_{2}−…−a_{n})|
∣xn−(ave−a1)∣+∣xn−(2×ave−a1−a2)∣+…+∣xn−(n×ave−a1−a2−…−an)∣
∣
x
n
−
c
1
∣
+
∣
x
n
−
c
2
∣
+
…
+
∣
x
n
−
c
n
∣
|x_{n}-c_{1}|+|x_{n}-c_{2}|+…+|x_{n}-c_{n}|
∣xn−c1∣+∣xn−c2∣+…+∣xn−cn∣
现在,我们就可以将其转化为一个数轴上求距离的集合问题。我们再将
∣
x
n
−
c
1
∣
|x_{n}-c_{1}|
∣xn−c1∣ 和
∣
x
n
−
c
n
−
1
∣
|x_{n}-c_{n-1}|
∣xn−cn−1∣ 分为一组,随后以此类推,发现
x
n
x_{n}
xn 的取值范围可以用下图来表示(最外层就是
∣
x
n
−
c
1
∣
|x_{n}-c_{1}|
∣xn−c1∣ 和
∣
x
n
−
c
n
−
1
∣
|x_{n}-c_{n-1}|
∣xn−cn−1∣,再向里层就以此类推),发现所有组别的取值范围的交集为中心蓝色的部分,即所有
c
i
c_{i}
ci 的中位数。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[1000001];
int c[1000001];
int n,ave;
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
ave+=a[i];
}
ave/=n;
for(int i=1;i<=n;i++)
c[i]=c[i-1]+ave-a[i-1];//等价
sort(c+1,c+n+1);
int ans=0,mid=c[(n+1)/2];
for(int i=1;i<=n;i++)
ans+=abs(mid-c[i]);
printf("%lld",ans);
return 0;
}