这题的详解比较漫长,建议直接看<<指南>>.
这里面的思维量还是不小的,犹如在做一道精巧的数学证明题,实际上这就是数学证明题.
我目前当然还没有实力能够独立证明出这样的结论.
简化为模型记忆一下:
Q:有n人围坐一圈,第i个人手中有a[i]张纸牌,现在他们需要在相邻的人之间传递纸牌,相邻的人传递一张纸牌的代价为1,求解使得最终所有人手中的纸牌数量相等所需要的最小代价.(假设数据有解,即a[i]之和为n的整数倍).
A:设a[i]之和即总纸牌数为T,将所有a[i]减去T / n,之后求a[i]前缀和,设为s[i].
现在对s[i]进行排序以便取中位数s[(n + 1) / 2],计算出:
Σi=1n abs(s[i] - s[(n + 1) / 2])
即为答案.
代码倒是很短.
注意从在排序后的1~n个数中,中位数在第(n + 1) / 2个.
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; int n, s[1000010]; long long t, ans; int main(){ scanf("%d", &n); for(int i = 1;i <= n; i++){ scanf("%d", s + i); t += s[i]; } for(int i = 1; i <= n; i++) s[i] += s[i - 1] - t / n; sort(s + 1, s + 1 + n); int mid = s[(n + 1) >> 1]; for(int i = 1; i <= n; i++) ans += abs(s[i] - mid); printf("%lld ", ans); return 0; }