糖果传递(思维,推式子)

题目:传送门

题意

有n个小朋友坐成一圈,每人有a[i]个糖果。

每人只能给左右两人传递糖果。

每人每次传递一个糖果代价为1。

求使所有人获得均等糖果的最小代价。

1n1000000
数据保证一定有解。

思路

设第一个人给了第 n 个人 x1 个糖果,第二个人给了第一个人 x2 个糖果,.....第 n 个人给了第 n - 1 个人 xn 个糖果。

答案就是 abs(x1) + abs(x2) + abs(x3) + ..... + abs(xn)

最终每个人的糖果数 result 是总的糖果数 s 除以人数 n,即 result = s / n;

对于第一个人来说有:

a[1] - x1 + x2 = result;

依次列出有:

a[2] - x2 + x3 = result;

a[3] - x3 + x4 = result;

....

化简一下有

x2 = x1 + result - a[1] = x1 - (a[1] - result); 

x3 = x2 + result - a[2] = x1 - (a[1] - result) - (a[2] - result);

......

我们让

c[1] = a[1] - result; 

c[2] = (a[1] - result) + (a[2] - result);

......

那么就有 xi =  x1 - c[i - 1];  则最终的答案就是 abs(x1) + abs(x1 - c[1]) + abs(x1 - c[2]) ..... + abs(x1 - c[n - 1]) ;

观察发现,abs(x1) + abs(x1 - c[1]) + abs(x1 - c[2]) ..... + abs(x1 - c[n - 1]) 类似于一维坐标上,所有点到某个定点的总距离和。

那么,我们可以对 c[i] 排序,定点为所有点中点时,距离和最小。

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define INF 0x3f3f3f3f
#define inf LLONG_MAX
#define PI acos(-1)
#define fir first
#define sec second
#define lb(x) ((x) & (-(x)))
#define dbg(x) cout<<#x<<" = "<<x<<endl;
using namespace std;

const int N = 1e6 + 5;

int n, a[N];

LL c[N];

void solve() {

    scanf("%d", &n);

    LL result = 0;

    rep(i, 1, n) scanf("%d", &a[i]), result += a[i];

    result /= n;

    rep(i, 1, n - 1) c[i] = c[i - 1] + a[i] - result;

    sort(c + 1, c + 1 + n);

    LL ans = 0LL;

    int pos = (n + 1) / 2;

    rep(i, 1, n) {

        ans += abs(c[i] - c[pos]);

    }

    printf("%lld
", ans);

}


int main() {

//    int _; scanf("%d", &_);
//    while(_--) solve();

    solve();

    return 0;
}
原文地址:https://www.cnblogs.com/Willems/p/13818003.html