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;
}

浙公网安备 33010602011771号