1. 程式人生 > >【貪心】糖果傳遞(數軸上求一個點,使得n點到其距離之和最小,該點為n點中位數)

【貪心】糖果傳遞(數軸上求一個點,使得n點到其距離之和最小,該點為n點中位數)

問題 K: 【貪心】糖果傳遞

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 2  解決: 2
[提交] [狀態] [討論版] [命題人:admin]

題目描述

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

輸入

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

輸出

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

樣例輸入

4
1
2
5
4

樣例輸出

4

[提交][狀態]

【分析】

這題很好的思維!

假設第i個孩子原始糖果數a[i],傳遞給他左邊孩子b[i]個糖果,b[i]可以為負數,即表示左邊孩子給了他-b[i]個。

最終所有人糖果平均數為aver。

則第 i 個孩子:a[i] - b[i] + b[i+1] = aver    =>   b[i+1] = b[i] - (a[i] - aver);

則有:

b[1] = b[1];

b[2] = b[1] - (a[1] - aver);

b[3] = b[2] - (a[2] - aver) = b[1] -(a[1] + a[2] - 2*aver);

.......

b[n] = b[1] - ( a[1]+a[2]+...+a[n-1] - (n-1)*aver) );

故代價之和

 ans=\sum_{i=1}^{n}| b_{i}| = \sum_{i=1}^{n} | b_{1} - [ \sum_{j=1}^{i-1}a_{j} -(i-1)*aver] |

a[j]已知,aver已知,故該式子只需確定b1,體現在數軸上就是已知n個點,求一個點b1使得n個點到它的距離之和最小。

這個問題問題的答案是:b1一定是n個點的中位數。

證明:

數軸上任取一點b1,不妨假設其左邊有4個點,右邊有1個。在b1不超出其左右臨近的兩點範圍之內,讓其向左移動dx,則距離之和會 - 4dx + 1dx,即減少了3dx。既然如此,我不如讓b1直接移動到其左相鄰的點上面,然後將該處點視為在b1右側也無妨。這時可認為b1左側有3點,右側有兩點。同樣的問題來臨,b1向左移動dx,其結果會使得距離之和減少1dx。

故點b1只要左右兩側點數不相等,則可繼續減少,中位數是最優的。

【程式碼】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll a[1010101],b[1010101],cnt[1010101];

int main()
{
    scanf("%d",&n);
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum+=a[i];
    }
    ll aver=sum/n;
    cnt[1]=0;
    for(int i=1;i<=n;i++)
        cnt[i]=cnt[i-1]+a[i-1]-aver;
    sort(cnt+1,cnt+1+n);
    ll ans=0;
    for(int i=1;i<=n;i++)
        ans+=abs(cnt[i]-cnt[(n+1)>>1]);
    printf("%lld\n",ans);
}