UVA11300 Spreading the Wealth

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

A::

先随便构造一个解,\(a_i\) 表示 \(i\) 给第 \(i+1\)\(a_i\) 个金币,\(a_i\) 可以小于零,\(a_n=0\)

显然所有解都是由其中一个解进行整体加减一个定值得到的。

\(\{a_1+t,a_2+t,\dot,a_n+t\}\) 也为一组合法的解。

转手的金币的数量为 \(\sum abs(a_i-t)\)

也就是选择一个合适的 \(t\) 使得 \(\sum abs(a_i-t)\) 最小,显然 \(t\) 应为 \(\{a_i\}\) 的中位数。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+91;
LL a[N],b[N],c[N];
int main(){
#ifdef LOCAL
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	while(1){
		int n; LL sum=0,ans=0;
		if(scanf("%d",&n)==EOF)break;
		if(n==0){puts("0");continue;}
		for(int i=1;i<=n;i++)
			scanf("%lld",&a[i]),sum+=a[i],b[i]=a[i]+b[i-1];
		sum/=n;
		// cout<<sum<<endl;
		for(int i=1;i<=n;i++)b[i]-=sum*i;
		// for(int i=1;i<=n;i++)cout<<b[i]<<' ';cout<<endl;
        nth_element(b+1,b+(n+1>>1),b+n+1);
		for(int i=1;i<=n;i++)ans+=abs(b[i]-b[n+1>>1]);
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2025-06-13 10:45  fzrcy  阅读(22)  评论(0)    收藏  举报