bzoj1045: [HAOI2008] 糖果传递

链接

  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=aveai si yi 的前缀和
  可以得到
x2=x1+s1x3=x1+s2......xn=x1+sn1

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

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

代码

//神奇题目
#include 
#include 
#include 
#define ll long long
#define maxn 1000010
using 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;
}

你可能感兴趣的:(#,数学杂题)