题目描述 圆桌旁坐着n个人,每人有一定数量的金币,金币总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数相等。你的任务是求出被转手的金币数量的最小值。比如,n=4,且4个人的金币数分别为1,2,5,4时,只需转移4枚金币(第3个人给第2个人两枚金币,第2个人和第4个人分别给第1 个人1枚金币)即可实现每人手中的金币数目相等。 输入 输入包含多组数据。每组数据第一行为整数n(n<=1 000 000),以下n行每行为一个整数,按逆时针顺序给出每个人拥有的金币数。输入结束标志为文件结束符(EOF)。 输出 对于每组数据,输出被转手金币数量的最小值。输入保证这个值在64位无符号整数范围内。 样例输入 3 100 100 100 4 1 2 5 4 样例输出 0 4
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 1000000+10; long long aa[maxn], c[maxn]; int main() { int n,i; int long long s,ans,m; while(scanf("%d",&n)!=EOF) { s=0; ans=0; for(i=1;i<=n;i++) { scanf("%lld",&aa[i]); s=s+aa[i]; } m=s/n; //m为平均每个人得到的金币 c[0]=0; for(i=1;i<=n;i++) c[i]=c[i-1]+aa[i]-m; //求出ci数组 int long long x; sort(c,c+n); //对数组ci排序(是为了找ci的中点) x=c[n/2]; //x为数组ci的中点,不管n是不是奇数,n直接除以2是没毛病的 for(i=0;i<n;i++) ans=ans+abs(x-c[i]); //ans为转手金币的最小值 printf("%lld\n",ans); } return 0; }
思路:(我也不会,只能百度一波)
m为平均每个人的金币,数组aa用来存放每个人的金币。
数学思维:设第i个人有ai个金币,xi为给出去的金币,对1号:a1-x1(1号给4号的)+x2(2号给1号的)=m;对2号:a2-x2+x3=m....
对1:x2=m-a1+x1=x1-c1,令c1=a1-m;对2:x3=x2+m-a2,用x1代x2得到:x3=x1-(a2+c1-m)=x1-c2,c2=c1+(a2-m);以此类推(将每个人送出去的金币最后化为含x1的表达式),我们就可以得到ci的关系c[i]=c[i-1]+aa[i]-m(核心!!!!!)。
被转手的金币数量最小值=|x1|+|x1-c1|+|x1-c2|+|x1-c3|+....+|x1-cn|;即用数学方法得到转手金币数量的最小值=>找一个点x1,使得它到c1,c2,c3...cn距离之和最小=>x1为他们的中点。