题目大意
有(n)个小朋友坐成一圈((1 leq n leq 1000000)),每人有(a_i)个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为(1)。求最小代价。
题解
环形实际上就是(n)种链形。(证明见下)
我们先考虑第(1)到(n)个小朋友形成链形的情况。
我们设
则此时对于每个(i),第(i)个小朋友传递的代价是(s_i)。
此时我们再回到环形,如果我们在第(k)个小朋友处拆成链形,则当(i geq k)时,第(i)个小朋友传递的代价为
当(i < k)时,第(i)个小朋友传递的代价为
根据我们前面的定义,可以得到,(s_n)恒为(0)。
所以当(i < k)时,第(i)个小朋友传递的代价也为
所以总代价为
根据贪心策略,显然这里的(s_k)应为({ s_i })中的中位数,排序处理一下即可。
#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define MAX_N (1000000 + 5)
#define SIZE (1 << 21)
#define abs(x) ((x) >= 0 ? (x) : -(x))
#define Getchar() (p1 == p2 && (p2 = (p1 = fr) + fread(fr, 1, SIZE, stdin), p1 == p2) ? EOF : *p1++)
using namespace std;
char fr[SIZE], * p1 = fr, * p2 = fr;
void Read(int & num)
{
num = 0;
char ch = Getchar();
while (!isdigit(ch)) ch = Getchar();
while (isdigit(ch)) num = num * 10 + ch - '0', ch = Getchar();
return;
}
int n;
int a[MAX_N];
int s[MAX_N];
long long ans;
int main()
{
Read(n);
long long tmp = 0;
for (int i = 1; i <= n; ++i)
{
Read(a[i]);
tmp += a[i];
}
tmp /= n;
for (int i = 1; i <= n; ++i)
{
s[i] = s[i - 1] + a[i] - tmp;
}
sort(s + 1, s + n + 1);
tmp = s[n >> 1];
for (int i = 1; i <= n; ++i)
{
ans += abs(s[i] - tmp);
}
printf("%lld", ans);
return 0;
}
终于把坑填上了。。。
证明:
设 (d_i) 为 (i) 向 (i+1) 传递的数量,显然 (a_i + d_{i-1} - d_{i} = overline{a}) 即 (d_{i-1} = overline{a} - a_i + d_{i}) 。
则 (d_i = sumlimits_{j=i+1}^{n}(overline{a} - a_j) + d_n) 。
令 (s_i = sumlimits_{j=i}^{n}(overline{a} - a_j)) 。
则 (d_i = s_{i+1} + d_n) 。
则 (ans = sumlimits_{i=1}^{n} |d_i| = sumlimits_{i=1}^{n}left|s_{i+1} + d_n
ight|) 。
当 (d_n = -s_{ ext{medium}}) 时 (ans) 最小。(这个容易证明吧)
所以一定存在一个 (d_i = 0) ,此时就在 (i) 和 (i+1) 中间拆开变成链即可。
话说证出来之后顺便就把题做完了啊。。。。