1. 程式人生 > >分金幣

分金幣

一行 意義 NPU lld 實現 文件 答案 任務 std

分金幣

題目描述:

? 圓桌旁坐著n個人,每人有一定數量的金幣,金幣總數能被n整除。每個人可以給他左右相鄰的人一些金幣,最終使得每個人的金幣數相等。你的任務是求出被轉手的金幣數量的最小值。比如,n=4,且4個人的金幣數分別為1,2,5,4時,只需轉移4枚金幣(第3個人給第2個人兩枚金幣,第2個人和第4個人分別給第1 個人1枚金幣)即可實現每人手中的金幣數目相等。

Input:

? 輸入包含多組數據。每組數據第一行為整數n(n<=1 000 000),以下n行每行為一個整數,按逆時針順序給出每個人擁有的金幣數。輸入結束標誌為文件結束符(EOF)。

Output:

? 對於每組數據,輸出被轉手金幣數量的最小值。輸入保證這個值在64位無符號整數範圍內。

Sample Input:

4 1 2 5 4

Sample Output:

4

題解:

假設M為每個人都擁有的金幣數,每個人的金幣變化是左右相鄰的人對其造成的影響
假設這n個人構成一個環,先假設n=4,設\(x1\)指1號給4號多少金幣,則\(x2\)代表2號給1號
多少金幣,其他的由此類推下去。
則對於1號來說,他給了4號金幣,則剩\(a1-x1\)
2號給了他金幣,則剩\(a1-x1+x2\)
註意這裏1號給4號和4號給1號的意義隱含在x1的符號裏面(很巧妙),其他的類似
由於最後要等於M,然後就可以得方程了
\(a1-x1+x2=M >> x2 = x1-(a1-M) = x1 - C1\\ a2-x2+x3=M >> x3 = x2-(a2-M)=x1-a1-a2-2*M = x1 - C2\\ a3-x3+x4=M >> x4 = x3-a1-a2-a3-3*M = x1 - C3\\ an-xn+x1=M >> xn = x1 - C(n-1)\)


看到這裏我們知道答案是所有xi的絕對值最小了
很顯然這就轉化為數軸上求一點x到\(ci\)距離和的最小值,然而這個點x其實就是序列\(ci\)(排
序後)的中位數,稍微想想應該知道

代碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 1000000+10;
long long A[maxn], C[maxn], tot, M;

int main(){
    int n;
    long long sum = 0;
    scanf("%d", &n);

    for(int i = 1; i <= n; ++i){
        scanf("%d", &A[i]);
        sum += A[i];
    }

    int arg = sum/n;

    C[0] = 0;

    for(int i = 1; i < n; ++i){
        C[i] = C[i-1] + A[i] - arg;
    }

    sort(C, C+n);

    long long x1 = C[n/2];
    long long ans = 0;

    for(int i = 0; i < n; ++i){
        ans += abs(x1 - C[i]);
    }

    printf("%lld\n", ans);
    return 0;
}

分金幣