【貪心】糖果傳遞(數軸上求一個點,使得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) );
故代價之和
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); }