Description
幼儿园的小孩们收到了一个有M颗糖果的大包裹,现在要把这些糖果分给N个小孩。每一个小孩都给出了一个期望的糖果数,如果没有达到他的期望值a[i],小孩就会生气。每差一个糖果,小孩的生气指数就会增加。可以认为他生气的程度等于他少得到的糖果数的平方。比如,Mirko想要得到32个糖果,但是只得到了29个。他少了3个,所以他的生气指数是9。不幸的是,糖果数不足以满足所有小孩的期望。所以我们应该采取最优的分配方法,使得最后小孩们的生气指数的和最小。
Input
第1行:2个整数M,N
第2..N+1行:第i+1行表示第i个小朋友期望值a[i]
Output
第1行:1个整数,表好似最小的总生气指数
Sample Input
10 4
4
5
2
3
Sample Output
4
Hint
1 ≤ N ≤ 100,000,1 ≤ M ≤ 2*109,M < SUM{a[i]}
结果不超过264-1
Source
COCI 2010/2011 CONTEST #1
【分析】(nodgd友情提供)
姑且可以称它为平均分配原则,事实上就是要使每个人分得的与期望的差值尽量平均。
我们只需要先求出a[i]总和与M的差值delta,并对a[i]排序
从最小的a[i]开始,如果a[i]*(N-i+1)>=derta,就说明剩下的差值可以平均分配,每个人的差值为derta/(N-i+1)或者derta/(N-i+1)+1,算出有多少个。如果a[i]*N<derta,就让这个人什么都不分,修改delta继续循环即可
【代码】
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
long long M,N,a[100005];
long long ans,sum;
void _in(long long &x)
{
char t=getchar();
while(t<'0'||'9'<t) t=getchar();
for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar());
}
void _init()
{
_in(M);_in(N);
for(int i=1;i<=N;i++)
{
_in(a[i]);
sum+=a[i];
}
}
void _qst_a(int l,int r)
{
int i=l,j=r;
long long ma=a[(i+j)>>1];
while(i<=j)
{
while(a[i]<ma) i++;
while(a[j]>ma) j--;
if(i<=j)
{
swap(a[i],a[j]);
i++;j--;
}
}
if(l<j) _qst_a(l,j);
if(i<r) _qst_a(i,r);
}
void _solve()
{
_qst_a(1,N);
long long delta=sum-M,avg;
avg=(double)(delta)/(double)(N);
for(int i=1;i<=N;i++)
{
if(a[i]>=avg)
{
int temp;
temp=delta-(N+1-i)*(delta/(N+1-i));
//temp为分得差值为(delta/(N+1-i)+1)的人数
ans+=temp*(delta/(N+1-i)+1)*(delta/(N+1-i)+1);
ans+=(N+1-i-temp)*(delta/(N+1-i))*(delta/(N+1-i));
printf("%I64d\n",ans);
return;
}
else
{
ans+=a[i]*a[i];
delta-=a[i];
avg=(double)(delta)/(double)(N-i);
}
}
}
int main()
{
_init();
_solve();
return 0;
}