寒假算法题练习1.8
题目
题目描述:
原题来自:HAOI 2008
有 n个小朋友坐成一圈,每人有 ai颗糖果。每人只能给左右两人传递糖果。每人每次传递一颗糖果的代价为 1 。求使所有人获得均等糖果的最小代价。
输入格式:
第一行有一个整数 n ,表示小朋友个数;
在接下来 n行中,每行一个整数 ai。
输出格式:
输出使所有人获得均等糖果的最小代价。
样例:
输入数据 1:
4
1
2
5
4
输出数据 1:
4
数据范围与提示:
对于 30% 的数据,n≤1000;
对于 100% 的数据,n≤10^6,保证答案可以用 64位有符号整数存储。
分析
保证答案可以用 64位有符号整数存储:使用long long型存储
每人只能给左右两人传递糖果:看做单向传递,传递个数可为正负数
a[i]:第i个小朋友原来拥有的糖果数
s[i]:第i个小朋友给第i+1个小朋友的糖果数
(因为围成圈,所以s[n]是第n个小朋友给第1个小朋友的糖果数)
由图中糖果给予关系知:给下一个人糖果数=自己原本拥有糖果数+上一个小朋友给自己的糖果数-均等糖果数
s[i]=a[i]+s[i-1]-avg;
则:
s[1]=s[1]-c[1] (c[1]=0)
s[2]=a[2]+s[1]-avg=s[1]-c[2] (c[2]=avg-a[2])
s[3]=a[3]+s[2]-avg=s[1]-c[3] (c[3]=2×avg-a[2]-a[3]=c[2]+avg-a3)
……
s[n]=a[n]+s[n-1]-avg=s[1]-c[n] (c[n]=n×avg-a[2]-a[3]-…-a[n]=c[n-1]+avg-a[n])
要求的最小代价即min{s[1]+……+s[n]},则转化为s[1]到c[i]的距离之和,所以s[1]为c[1]~c[n]的中位数
代码
#include <iostream>
#include<algorithm>
using namespace std;
long long i,n,weight=0,sum=0,avg, a[1000001],s[1000001],c[1000001];
int main()
{
cin>>n;//读入
for(i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];//求和
}
avg=sum/n;//平均数
c[1]=0;
for(i=2;i<=n;i++)
{
c[i]=c[i-1]+avg-a[i];//c[i]的关系由上面等式得到
}
sort(c+1,c+n+1);//对c[i]排序
s[1]=c[n/2+1];//c[i]的中位数
for(i=1;i<=n;i++)
{
weight+=abs(s[1]-c[i]);//求s[1]到c[i]的距离之和
}
cout<<weight;//输出最小权重
}