HYSBZ-1045 糖果传递

有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。

假设当所有人获得均等的糖果的时候:

  1. 每个人手上的糖果的数量为(ave)

  2. (i)个人初始时的糖果数量为(A_i)

  3. (i)个人给了前一个人(X_i)个糖果(如果(X_i)是负数,代表前一个人实际上的给了第(i)个人(X_i)个糖果)

那么对于每个人,都满足等式

[A_i-X_i+X_{(i+1)\%n}=ave ]

然后可以列出n条等式

[A_0-X_0+X_1=ave\ A_1-X_1+X_2=ave\ ...\ A_{n-1}-X_{n-1}+X_0=ave\ ]

最终的答案应该是(sum_{i=0}^{n-1}|X_{i}|)

实际上以上的其中一条等式能够由其他的(n-1)条等式得到.

不同的等式只有(n-1)条,未知数有(n)个,不能直接解.

假设(X_0)是已知的值,可以推出所有的(X)的值

[X_1=ave-A_0+X_0=X_0-(A_0-ave)\ X_2=ave-A_1+X_1=X_1-(A_1-ave)=X_0-(A_0-ave)-(A_1-ave)\ ...\ X_{n-1}=X_0-sum_{i=0}^{n-2}(A_i-ave) ]

定义(C_k=C_{k-1}-(A_i-ave))

那么(|X_k|=|X_0-C_k|)

如何让(sum_{i=0}^{n-1}|X_{i}|)变得尽量小,

可以发现,(|X_0-C_k|)可以看作是数轴上(X_0)(C_k)的距离,

(X_0),(C_1),(C_2),...,(C_{n-1}),都列在一条数轴上,

找到其中的一个点,让这个点到其他所有的点的距离的和最小.

显然,这几个点之中最靠中间的点,就是到其他所有点的距离的和最小的点.

那么这个距离的和就是答案

应该如何假设(X_0)的值?

(X_0)的含义是第(0)个人给第(n-1)个人的糖果的数量.

实际上,从第二个人开始,每人给前一个人(X_i)个糖果,到最后第(n-1)个人手上的糖果数就应该是(ave)了.

所以(X_0)应该是(0).

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

static ll n, sum, ave, mid, ans, a[1100100], c[1100100];

int main()
{
    scanf("%lld", &n);
    for(ll i = 0; i < n; ++i)
    {
        scanf("%lld", &a[i]);
        sum += a[i];
    }
    ave = sum/n;

    c[0] = 0;
    for(int i = 1; i < n; ++i)
    {
        c[i] = c[i-1]+a[i]-ave;
    }

    sort(c, c+n);
    mid = c[n/2];
    for(int i = 0; i < n; ++i)
        ans += abs(c[i] - mid);
    printf("%lld
", ans);
}

原文地址:https://www.cnblogs.com/zzidun-pavo/p/12482756.html