1045: [HAOI2008] 糖果传递
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 4394 Solved: 2155
[Submit][Status][Discuss]
Description
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
Input
第一行一个正整数nn<=1‘000‘000,表示小朋友的个数.
接下来n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.
Output
求使所有人获得均等糖果的最小代价。
Sample Input
4
1
2
5
4
Sample Output
4
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1145
Solution
显然最后每个小朋友分到的糖数 s 是可以直接算的。。。
假设刚开始每个第 i 个小朋友有 k [ i ] 个糖。。第 i 个小朋友给第 i - 1 个小朋友 t [ i ] 个糖,第 n 个小朋友给第一个小朋友 t [ n ] 个糖。。
于是可以列出方程: k [ i ] - t [ i ] + t [ i + 1 ] = s
记 C [ i ] = ∑ ( k [ j ] - s ) (1 <= j <= i )
于是:
t [ 2 ] = s - k [ 1 ] + t [ 1 ] = t [ 1 ] - C [ 1 ]
t [ 3 ] = s - k [ 2 ] + t [ 2 ] = 2*s - k [ 2 ] - k [ 1 ] + t [ 1 ] = t [ 1 ] - C [ 2 ]
t [ 4 ] = t [ 1 ] - C [ 3 ]
。。。
我们要求的是 ∑ | t [ i ] - C [ i - 1 ] | ,实质上就是给出数轴上若干个点 C0 ,C1 ,C2 。。。。 然后求一个点 x 使得总距离最小。。。
显然用最中间的那个点是最优的。。。
代码
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #define N 1000050 #define LL long long using namespace std; inline int Read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int n; int k[N],t[N]; LL mid,ans,s; int main(){ n=Read(); for(int i=1;i<=n;i++){ k[i]=Read();s+=k[i]; } s=s/n; for(int i=1;i<=n;i++) t[i]=t[i-1]-k[i]+s; sort(t+1,t+n+1); mid=t[n/2]; for(int i=1;i<=n;i++) ans+=abs(t[i]-mid); printf("%lld\n",ans); return 0; }
This passage is made by Iscream-2001.