bzoj3293 分金币

题目链接

problem

圆桌上坐着n个人,每人有一定数量的金币,金币总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使
得每个人的金币数目相等。你的任务是求出被转手的金币数量的最小值。

solution

肯定会有至少一个相邻位置之间没有进行传递。
枚举这个位置,假设为k。用x表示每个人最终应有的硬币数量,\(S_i\)表示前i个人所有的硬币数量和-前i个人应有的硬币数之和。那么在第i个人与第\(i-1\)个人之间进行传递的硬币数量就是\(|S_i-S_k|\)。枚举\(S_k\),统计答案即可。

code

/*
* @Author: wxyww
* @Date:   2019-12-14 19:29:29
* @Last Modified time: 2019-12-14 20:23:07
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 2000010;
ll read() {
	ll x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1; c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0'; c = getchar();
	}
	return x * f;
}
ll s[N],a[N];
int main() {
	int n = read();
	ll sum = 0;
	for(int i = 1;i <= n;++i) a[i] = read(),sum += a[i];

	ll x = sum / n;
	for(int i = 1;i <= n;++i) a[i] = a[i - 1] + a[i] - x;
	
	sort(a + 1,a + n + 1);

	for(int i = n;i >= 1;--i) s[i] = s[i + 1] + a[i];
	ll now = 0;
	ll ans = 1e16;
	for(int i = 1;i <= n;++i) {
		now += a[i];
		ans = min(ans,a[i] * i - now + s[i + 1] - a[i] * (n - i));
	}
	cout<<ans;
	return 0;
}
posted @ 2019-12-14 20:38  wxyww  阅读(130)  评论(0编辑  收藏  举报