一、题目链接
二、题目大意
有 n n n个小朋友坐成一圈,每人有 a i a_i ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为 1 1 1。求使所有人获得均等糖果的最小代价。
数据范围: 1 ≤ n ≤ 1 0 6 1\leq n \leq10^6 1≤n≤106。
三、题目分析
-
假设 T [ i ] T[i] T[i]表示第 i i i个人向第 i − 1 i−1 i−1个人传了 T [ i ] T[i] T[i]张牌 ( T [ 1 ] T[1] T[1]表示第一个向第 n n n个),值为负表示反向。代价为 ∑ 1 × ∣ T [ i ] ∣ \sum 1\times|T[i]| ∑1×∣T[i]∣。
-
由于传递后每个人的牌都为 a v e r a g e average average ,所以可以列出一系列方程
a [ 1 ] + T [ 2 ] − T [ 1 ] = a v e r a g e a [ 2 ] + T [ 3 ] − T [ 2 ] = a v e r a g e … … a [ n ] + T [ 1 ] − T [ n ] = a v e r a g e (1) \begin{gather*} a[1]+T[2]−T[1]=average\\ a[2]+T[3]−T[2]=average\\ ……\\ a[n]+T[1]−T[n]=average \end{gather*}\tag{1} a[1]+T[2]−T[1]=averagea[2]+T[3]−T[2]=average……a[n]+T[1]−T[n]=average(1) -
用 T [ 1 ] T[1] T[1]表示 T [ 2 ] , T [ 3 ] , … , T [ n ] T[2],T[3],…,T[n] T[2],T[3],…,T[n]可得:
T [ 2 ] = T [ 1 ] − ( a [ 1 ] − a v e r a g e ) T [ 3 ] = T [ 1 ] − ( a [ 2 ] + a [ 1 ] − 2 × a v e r a g e ) … … T [ n ] = T [ 1 ] − ( a [ n − 1 ] + a [ n − 2 ] + ⋯ + a [ 1 ] − ( n − 1 ) × a v e r a g e ) (2) \begin{gather*} T[2]=T[1]−(a[1]−average)\\ T[3]=T[1]−(a[2]+a[1]−2 \times average)\\ ……\\ T[n]=T[1]−(a[n−1]+a[n−2]+⋯+a[1]−(n−1) \times average)\\ \end{gather*}\tag{2} T[2]=T[1]−(a[1]−average)T[3]=T[1]−(a[2]+a[1]−2×average)……T[n]=T[1]−(a[n−1]+a[n−2]+⋯+a[1]−(n−1)×average)(2) -
设 s i s_i si为前 i i i个人糖果数与平均值的差值的前缀和
T [ 1 ] = T [ 1 ] − s [ n ] T [ 2 ] = T [ 1 ] − s [ 1 ] T [ 3 ] = T [ 1 ] − s [ 2 ] . . . . . . T [ n ] = T [ 1 ] − s [ n − 1 ] (3) \begin{gather*} T[1]=T[1]-s[n]\\ T[2]=T[1]−s[1]\\ T[3]=T[1]−s[2]\\ ......\\ T[n]=T[1]−s[n-1]\\ \end{gather*}\tag{3} T[1]=T[1]−s[n]T[2]=T[1]−s[1]T[3]=T[1]−s[2]......T[n]=T[1]−s[n−1](3)
操作次数可以表示为 ∑ ∣ T [ i ] ∣ = ∑ ∣ T [ 1 ] − s [ i ] ∣ \sum|T[i]|=\sum|T[1]−s[i]| ∑∣T[i]∣=∑∣T[1]−s[i]∣,那么原问题变成了求 T [ 1 ] T[1] T[1]的值使得上述求和最小。 -
此时,对 T [ 1 ] T[1] T[1]的选择即可转化为数轴上几点 s [ i ] s[i] s[i]到动点 T [ 1 ] T[1] T[1]距离和的最小值。很显然:
- 若 n n n为奇数,当 T [ 1 ] T[1] T[1]为 s [ i ] s[i] s[i]中位数时和最小。
- 若 n n n为偶数,当 T [ 1 ] T[1] T[1]为 s [ i ] s[i] s[i]中间两数之间任何值时和最小。
四、正解程序
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll a[1000010],b[1000010],mid,ans,average,n;
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
average+=a[i];
}
average/=n;
for(ll i=1;i<=n;i++)
b[i]=b[i-1]+average-a[i];
sort(b+1,b+1+n);
ll temp=b[n/2+1],ans=0;
for(ll i=1;i<=n;i++)
ans+=abs(b[i]-temp);
printf("%lld",ans);
return 0;
}