luogu P2512 [HAOI2008]糖果传递

题面传送门
又是数学题。
a i a_i ai 为本来钱数, b i b_i bi 为给后一个人多少钱, m m m 为平均分的钱数。
则: a 1 − b 1 + b 2 = m a_1-b_1+b_2=m a1b1+b2=m
a 1 − b 1 + b 2 = m a_1-b_1+b_2=m a1b1+b2=m
b 2 = b 1 − ( a 1 − m ) b_2=b_1-(a_1-m) b2=b1(a1m)
a 2 − b 2 + b 3 = m a_2-b_2+b_3=m a2b2+b3=m
b 3 = 2 m − a 2 + b 1 − a 1 b_3=2m-a_2+b_1-a_1 b3=2ma2+b1a1
所以 可得 b 3 = b 1 − ( a 1 − m ) − ( a 2 − m ) b_3=b_1-(a_1-m)-(a_2-m) b3=b1(a1m)(a2m)
以此类推, b i = b 1 − ∑ j = 1 i − 1 ( a j − m ) b_i=b_1-\sum\limits_{j=1}^{i-1}{(a_j-m)} bi=b1j=1i1(ajm)
所以原题变为求 ∑ i = 1 n ∣ b 1 − ∑ 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|} i=1nb1j=1i1(ajm)第二重循环可以用前缀和优化,那么只要让 b 1 b_1 b1 最小就 行了。找中点呗!
代码实现:

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值