1. 程式人生 > >[bzoj1045][洛谷P2512][HAOI2008] 糖果傳遞

[bzoj1045][洛谷P2512][HAOI2008] 糖果傳遞

cst std using 中位數 ons 一行 ans logs 其中

Description

有n個小朋友坐成一圈,每人有ai個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞一個糖果代價為1。

Input

第一行一個正整數nn<=1‘000‘000,表示小朋友的個數.
接下來n行,每行一個整數ai,表示第i個小朋友得到的糖果的顆數.

Output

求使所有人獲得均等糖果的最小代價。

Sample Input

4

1

2

5

4

Sample Output

4


想法

設第\(i\)個小朋友從他左邊小朋友那裏得到 \(l_i\) 個糖果,向他右邊的小朋友傳遞 \(r_i\) 個糖果
\(l_i\)\(r_i\) 都可以為負數)
顯然 \(l_i=r_{i-1}\)

,特殊地 \(l_1=r_n\)
\(p\)為最終每個小朋友手中的糖果數
則有 \(l_i+a_i-r_i=p\) , 即 $ r_i=l_i+(a_i-p) $
而我們又有 \(l_i=r_{i-1}\)
一直遞歸下去有 $ r_i=l_1+(a_1-p)+(a_2-p)+(a_3-p)+…+(a_i-p) $
最終答案為 \(|r_1|+|r_2|+…+|r_n|\)
我們可以記下 \(a_i-p\) 的前綴和為 \(sum_i\)
那麽 \(ans=|l_1+sum_1|+|l_1+sum_2|+…+|l_1+sum_n|\)
絕對值是個美妙的東西,\(|l_1+sum_i|\) 可想為數軸上 \(-l_i\)
\(sum_i\) 的距離
那麽\(ans\)的最小值在 \(-l_1\)\(sum_i\) 中位數時取到

求出\(sum_i\)及其中位數後計算即可。


代碼

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long ll;
const int N = 1000005;

int a[N];
ll sum[N],p;
int n;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        p+=a[i];        
    }
    p=p/n;
    sum[0]=0;
    for(int i=1;i<=n;i++) 
        sum[i]=sum[i-1]+a[i]-p;
    
    sort(sum+1,sum+1+n);
    ll l=sum[n/2+1],ans=0; //註意:中位數為n/2+1而不是n/2
    for(int i=1;i<=n;i++)
        ans+=abs(sum[i]-l);
    printf("%lld\n",ans);
    
    return 0;    
}

[bzoj1045][洛谷P2512][HAOI2008] 糖果傳遞