1. 程式人生 > >[HAOI2008]糖果傳遞

[HAOI2008]糖果傳遞

code getc element 題解 輸出 前綴和 clas print 增加

題目描述

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

輸入輸出格式

輸入格式:

小朋友個數n 下面n行 ai

輸出格式:

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

輸入輸出樣例

輸入樣例#1:

4
1
2
5
4
輸出樣例#1:
4

說明

對於100%的數據 \(n<=10^6\)

題解

環形均分紙牌

先考慮線性的均分紙牌是怎麽做的

先求出平均值ave

然後將每堆的牌數-ave

表示需要增加/扔出多少張紙牌

然後求一個前綴和Sum

把n個前綴和加起來就是答案了

那麽環形的均分紙牌也是類似

只是我們要考慮破環為鏈

那麽我們就是要求\(\sum_{i=1}^{n}{Sum[i]-Sum[t]}\)

最小

這個\(t\)顯然就是所有\(Sum[]\)的中位數所對應的位置

代碼

#include<cstdio>
#include<algorithm>
# define LL long long
const int M = 1000005 ;
using namespace std ;
inline LL read() {
    char c = getchar() ; LL x = 0 , w = 1 ;
    while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    return x*w ;
}

int n , mid ;
LL v[M] , ave , sum[M] , Ans ;
int main() {
    n = read() ; mid = (n + 1) >> 1 ;
    for(int i = 1 ; i <= n ; i ++) 
        v[i] = read() , ave += v[i] ;
    ave /= n ;
    for(int i = 1 ; i <= n ; i ++) v[i] -= ave ;
    for(int i = 1 ; i <= n ; i ++) sum[i] = sum[i - 1] + v[i] ;
    nth_element(sum + 1 , sum + mid , sum + n + 1) ;
    for(int i = 1 ; i <= n ; i ++) Ans += abs(sum[i] - sum[mid]) ;
    printf("%lld\n",Ans) ;
    return 0 ;
}

[HAOI2008]糖果傳遞