cogs 1430. [UVa 11300]分金幣
1430. [UVa 11300]分金幣
★☆ 輸入文件:Wealth.in
輸出文件:Wealth.out
簡單對比
時間限制:1 s 內存限制:256 MB
【題目描述】
圓桌旁坐著n個人,每個人有一定數量的金幣,金幣數總能被n整除。每個人可以給他左右相鄰的人一些金幣,最終使得每個人的金幣數相等。你的任務是求出被轉手的金幣數量最小值。
比如,n=4,且4個人的金幣數分別是1,2,5,4時,只需轉移4枚金幣(第3個人給第2個人2枚金幣,第2個人和第4個人分別給第一個人1枚金幣)即可實現每人手中的金幣數相等。
【輸入格式】
輸入包括多組數據。每組數據的第一行為整數n(n≤1 000 000),以下n行每行為一個整數,按逆時針的順序給出每個人擁有的金幣數。輸入結束標誌為文件結束符(EOF).
【輸出格式】
對於每組數據,輸出被轉手的金幣數量的最小值。
輸入保證這個值在64位無符號整數範圍內。
【樣例輸入】
3
100
100
100
4
1
2
5
4
【樣例輸出】
0
4
【題目來源】
- Spreading the Wealth ,UVa 11300
思路: 這道題目看起來很復雜,讓我們慢慢分析。首先,最終每個人的金幣數量可以計算出來,他等於金幣總數除以人數n。接下來我們用M來表示每個人最終擁有的金幣數。 假設有4個人,按順序編號為1,2,3,。假設1號給2號3枚金幣,然後2號又給了1號5枚金幣,這實際上等價於2號給1號2枚金幣,而1號什麽也沒給2號。這樣,可以設x2
任意找一個點,比如上圖中的灰點。他的左邊有4個輸入點,右邊有2個輸入點。把他往左移動一點,不要移的太多,以免碰到輸入點。假設移動了d單位距離。則灰點左邊4個點到他的距離個減少了d,右邊兩個點到他的距離各增加了d,但總的來說,距離之和減少了2d。
如果灰點左邊有2個點,右邊有4個點,道理類似,不過應該向右移動。換句話說,只要灰點左右的輸入點數不一樣多,就不是最優解。什麽情況下左右的輸入點一樣多呢?如果輸入點一共有奇數個,則灰點必須和中間的那個點重合(中位數);如果有偶數個,則灰點可以位於最中間的兩個點之間的任意位置(還是中位數)。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 1000100 using namespace std; long long n,tot,ans; long long val[MAXN],C[MAXN]; int main(){ freopen("Wealth.in","r",stdin); freopen("Wealth.out","w",stdout); while(scanf("%d",&n)!=EOF){ tot=0; for(int i=1;i<=n;i++){ scanf("%I64d",&val[i]); tot+=val[i]; } tot/=n;C[0]=0; for(int i=1;i<n;i++) C[i]=C[i-1]+val[i]-tot; sort(C,C+n); long long x1=C[n/2];ans=0; for(int i=0;i<n;i++) ans+=abs(x1-C[i]); printf("%I64d\n",ans); } }
cogs 1430. [UVa 11300]分金幣