B1045 糖果傳遞 數學
阿新 • • 發佈:2018-08-17
發現 cstring return style put mem 模擬 推導 using
糖果傳遞,一開始就想到了n^2的模擬貪心算法,但是一看,數據範圍太大,好像只有O(N)能過。。。沒啥方法,只好看題解,之後發現,woc,還有這種操作?
這個題直接可以用數學證明。。。
證明如下:
首先,最終每個小朋友的糖果數量可以計算出來,等於糖果總數除以n,用ave表示。 假設標號為i的小朋友開始有Ai顆糖果,Xi表示第i個小朋友給了第i-1個小朋友Xi顆糖果,如果Xi<0,說明第i-1個小朋友給了第i個小朋友Xi顆糖果,X1表示第一個小朋友給第n個小朋友的糖果數量。 所以最後的答案就是ans=|X1| + |X2| + |X3| + ……+ |Xn|。 對於第一個小朋友,他給了第n個小朋友X1顆糖果,還剩A1-X1顆糖果;但因為第2個小朋友給了他X2顆糖果,所以最後還剩A1-X1+X2顆糖果。根據題意,最後的糖果數量等於ave,即得到了一個方程:A1-X1+X2=ave。 同理,對於第2個小朋友,有A2-X2+X3=ave。最終,我們可以得到n個方程,一共有n個變量,但是因為從前n-1個方程可以推導出最後一個方程,所以實際上只有n-1個方程是有用的。 盡管無法直接解出答案,但可以用X1表示出其他的Xi,那麽本題就變成了單變量的極值問題。 對於第1個小朋友,A1-X1+X2=ave -> X2=ave-A1+X1 = X1-C1(假設C1=A1-ave,下面類似) 對於第2個小朋友,A2-X2+X3=ave -> X3=ave-A2+X2=2ave-A1-A2+X1=X1-C2 對於第3個小朋友,A3-X3+X4=ave -> X4=ave-A3+X3=3ave-A1-A2-A3+X1=X1-C3 …… 對於第n個小朋友,An-Xn+X1=ave。 我們希望Xi的絕對值之和盡量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要盡量小。註意到|X1-Ci|的幾何意義是數軸上的點X1到Ci的距離,所以問題變成了:給定數軸上的n個點,找出一個到他們的距離之和盡量小的點,而這個點就是這些數中的中位數,證明略。
偷來的證明。。。
題目:
Description 有n個小朋友坐成一圈,每人有ai個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞一個糖果代價為1。 Input 第一行一個正整數nn<=1‘000‘000,表示小朋友的個數. 接下來n行,每行一個整數ai,表示第i個小朋友得到的糖果的顆數. Output 求使所有人獲得均等糖果的最小代價。 Sample Input 4 1 2 5 4 Sample Output 4
代碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < ‘0‘ || c > ‘9‘) if(c == ‘-‘) op = 1; x = c - ‘0‘; while(c = getchar(), c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar(‘-‘), x = -x; if(x >= 10) write(x / 10); putchar(‘0‘ + x % 10); } ll c[1000010],tot = 0,n,p[1000010]; ll ans = 0; int main() { read(n); duke(i,1,n) { read(p[i]); tot += p[i]; } tot /= n; duke(i,2,n) { c[i] = c[i - 1] + p[i] - tot; } ll x; sort(c + 1,c + n + 1); x = c[n / 2 + 1]; duke(i,1,n) { ans += (ll)(abs(x - c[i])); } printf("%lld\n",ans); return 0; } /* 4 1 2 5 4 */
B1045 糖果傳遞 數學