bzoj1045: [HAOI2008] 糖果传递

来源:互联网 发布:做淘宝天猫优惠券 编辑:程序博客网 时间:2024/05/22 15:37

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=1045

题解

  因为数组开成了int导致1A连击中止..本次1A连击数:2
  设第i个人给第i-1个人的糖果数为xi,其正负可以表示给糖果的方向,正表示i给i-1,负表示i-1给i。
  那就是最小化|x1|+|x2|+...|xi|+...+|xn|
  这样没法做,需要找等量关系消元。设ave=ni=1ain
  那么

a1x1+x2=avea2x2+x3=ave......anxn+x1=ave

  令yi=aveaisiyi的前缀和
  可以得到
x2=x1+s1x3=x1+s2......xn=x1+sn1

  那就成了最小化
|x1|+|x1+s1|+|x2+s2|+...+|x1+sn1|

  将|x1+si|写成|x1(si)|,就成了几何问题:在数轴上找一个点x1,使得其到s1s2……sn的距离和最小,直接找si的中位数作为x1的值就行了。

代码

//神奇题目#include <cstdio>#include <algorithm>#include <cmath>#define ll long long#define maxn 1000010using namespace std;ll x[maxn], y[maxn], N, a[maxn], tmp[maxn];ll read(ll x=0){    char c=getchar();    while(c<48 or c>57)c=getchar();    while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48, c=getchar();    return x;}int main(){    ll i, ans=0;    N=read();    for(i=1;i<=N;i++)a[i]=read(), a[0]+=a[i];    a[0]/=N;    for(i=1;i<=N;i++)y[i]=a[0]-a[i]+y[i-1];    for(i=1;i<=N;i++)tmp[i]=-y[i];    sort(tmp,tmp+N);    x[1]=tmp[(0+N+1)>>1];    for(i=2;i<=N;i++)x[i]=y[i-1]+x[1];    for(i=1;i<=N;i++)ans+=abs(x[i]);    printf("%lld",ans);    return 0;}
0 0