luogu P2512 [HAOI2008]糖果传递
题面传送门
又是数学题。
设 \(a_i\) 为本来钱数,\(b_i\) 为给后一个人多少钱,\(m\) 为平均分的钱数。
则: \(a_1-b_1+b_2=m\)
\(a_1-b_1+b_2=m\)
\(b_2=b_1-(a_1-m)\)
\(a_2-b_2+b_3=m\)
\(b_3=2m-a_2+b_1-a_1\)
所以 可得\(b_3=b_1-(a_1-m)-(a_2-m)\)
以此类推,\(b_i=b_1-\sum\limits_{j=1}^{i-1}{(a_j-m)}\)
所以原题变为求\(\sum\limits_{i=1}^{n}{\left|b_1-\sum\limits_{j=1}^{i-1}{(a_j-m)}\right|}\)第二重循环可以用前缀和优化,那么只要让\(b_1\) 最小就 行了。找中点呗!
代码实现:
#include<cstdio>
#include<cmath>
#include<algorithm>
#define abs(x) ((x)>0?(x):-(x))
using namespace std;
int m,n;
long long ans,tot,pus,now,q[1000039],a[1000039];
inline void read(long long &x){
char s=getchar();x=0;
while(s<48||s>57) s=getchar();
while(s>=48&&s<=57) x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
int main(){
register int i;
scanf("%d",&n);
for(i=1;i<=n;i++)read(a[i]),ans+=a[i];
m=ans/n;
for(i=1;i<=n;i++) a[i]-=m,q[i]=q[i-1]+a[i];
sort(q+1,q+n+1);
now=q[(int)ceil(n*1.0/2)];
for(i=1;i<=n;i++) tot+=abs(q[i]-now);
printf("%lld",tot);
return 0;
}