圆桌旁坐着n个人,每人有一定数量的金币,金币总数总能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数相等,你的任务是求出被转手的金币数量的最小值。
输入第一行为整数n(n<=1000000)以下n行每行为一个整数,按逆时针顺序给出每个人拥有的金币数。
对于每组数据输出被转手金币数量的最小值。
eg:
3
100
100
100
0
4
1
2
5
4
4
初看与蓝桥的海盗分金问题类似,单仔细的分析会发现完全不同,此题与海盗分金相比更麻烦复杂;
题目数据已知每人手中金币数,则易求出总金币数MZ=x1+x2+x3+...xn;
则最终局面每人手中的金币数M=MZ/n;
则对于初始局面x1,x2,x3,x4;设在整个过程中总发生第n人给第n-1人An枚金币(An可为负),而对于n=1时为第一人给第n个人金币数。
则对于此题结果为MIN{A1+A2+A3+A4};
则可得下式:
x1-A1+A2=M;=>A1=x1+A2-M;
x2-A2+A3=M;=>A2=x2+A3-M;
x3-A3+A4=M;=>A3=x3+A4-M;
x4-A4+A1=M;=>A4=x4+A1-M;
明显对于该式虽然有四个未知数四个等式,但并不能计算的出结果。即在四个方程中只有3个可用,即对于n个则前n-1个可用;
所以设A1已知;可推导出
A1
A2=A1+M-x1;
A3=A1+2M-x1-x2;
A4=A1+3M-x1-x2-x3;
则结果为MIN{A1+(A1+M-x1)+(A1+2M-x1-x2)+(A1+2M-x1-x2-x3)}
=>MIN{A1+(A1+M-x1)+(A1+2M-(x1+x2))+(A1+2M-(x1+x2+x3))}
=>MIN{A1+(A1-[x1-M])+(A1-[(x1+x2)-2M])+(A1-[(x1+x2+x3)-2M])}
在此处即可求出满足条件的A1(之后依据之前的等式可算出);
{
最后一步问题可等价为有n个点分布于一个数轴上从中选出一个点使其到其余各点的距离和最小
}
#include<stdio.h>
#define INF 99999999
void compare(int x,int y);
long long pe[1000001]={},sum[1000001]={};
int main()
{
int n=1000000;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&pe[i]);
sum[i]=sum[i-1]+pe[i];
}
int m=sum[n]/n;
for(int i=2;i<=n;i++)
pe[i]=sum[i-1]-(i-1)*m;
pe[1]=0;
compare(1,n);
int num=pe[(1+n)/2];
int ans=0;
for(int i=1;i<=n;i++)
{
int g=num-pe[i];
ans+=g<0?-g:g;
}
printf("%d",ans);
return 0;
}
void compare(int x,int y)
{
if(x>=y) return ;
int r,l,cur;
l=cur=x;r=y;
while(l<r)
{
for(;l<r;r--)
if(pe[r]<pe[cur])
{int t=pe[r];pe[r]=pe[cur];pe[cur]=t;cur=r;break;}
for(;l<r;l++)
if(pe[l]>pe[cur])
{int t=pe[l];pe[l]=pe[cur];pe[cur]=t;cur=l;break;}
}
compare(x,cur-1);
compare(cur+1,y);
}