1. 程式人生 > >B1045 糖果傳遞 數學

B1045 糖果傳遞 數學

發現 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<=1000000,表示小朋友的個數.
接下來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 糖果傳遞 數學