码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj1045] [HAOI2008] 糖果传递

时间:2019-02-15 13:52:56      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:pre   line   多少   sample   long   code   def   fine   const   

Description

有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。

Input

第一行一个正整数nn<=1‘000‘000,表示小朋友的个数.

接下来n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.

Output

求使所有人获得均等糖果的最小代价。

Sample Input

4
1
2
5
4

Sample Output

4

Solution

\(x_i\)表示第\(i\)个人给了第\(i-1\)个人多少,负数表示反着给,\(x_1\)表示\(1\)号给\(n\)号。

\(s=\sum_{i=1}^{n}a_i/n\),即平均数。

所以显然可以得到一系列等式:
\[ s=a_1-x_1+x_2\s=a_2-x_2+x_3\\vdots \s=a_n-x_n+x_1 \]
但是注意到最后一个可以被前面的推出来,所以不能解出\(x\),可以考虑用\(x_1\)表示剩下的\(x\),得:
\[ x_2=s-a_1+x_1\x_3=2s-a_1-a_2+x_1\\\vdots\x_n=a_n-s+x_1=(n-1)s-\sum_{i=1}^{n-1}a_i+x_1 \]
然后可以发现前面那一块可以\(O(n)\)算出来,设为\(c_i\),那么问题就转化为了最小化:
\[ f(x)=\sum_{i=1}^{n}|c_i-x| \]
这个可以看成一维数轴上一个点和一堆确定的点的距离和,取中点就好了。

#include<bits/stdc++.h>
using namespace std;

#define int long long 
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 1e6+10;

int n,a[maxn],c[maxn],ans;

signed main() {
    read(n);int sum=0;
    for(int i=1;i<=n;i++) read(a[i]),sum+=a[i];sum/=n;
    for(int i=2;i<=n;i++) c[i]=c[i-1]+sum-a[i-1];
    int mid=(n+1)>>1;nth_element(c+1,c+mid,c+n+1);
    for(int i=1;i<=n;i++) ans+=abs(c[mid]-c[i]);write(ans);
    return 0;
}

[bzoj1045] [HAOI2008] 糖果传递

标签:pre   line   多少   sample   long   code   def   fine   const   

原文地址:https://www.cnblogs.com/hbyer/p/10382952.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!