題意:有n個事件,每一個事件有一個嚴重程度,m我的(m>=n),你要讓m我的去背鍋,每一個人只能背一個事件的鍋,可是一個事件能夠由不少人背。讓你使得這m我的所承受的嚴重程度的方差最小化。this
考慮一開始n我的各背一個事件,記錄下該初始狀態下的ans。而後分配剩下的m-n我的。堆裏存儲每一個事件的嚴重程度x和當前背鍋人數y,按照x*x/y-x*x/(y+1.0)(這個值是該事件當前提供的方差*n-給當前的事件多分配一我的所能提供的方差*n,即給它多分配一我的所能給方差帶來的改進量,很容易推出來)從大到小排序,而後依次從堆頂取出元素,把一我的分給這個事件,再放回堆便可,而後對初始狀態的ans減去這個值,直到堆頂元素的這個值小於零。spa
#include<cstdio> #include<queue> using namespace std; const double EPS=0.00000001; double ave; struct data{ double x,y,val; data(const double &x,const double &y){ this->x=x; this->y=y; val=x*x/y-x*x/(y+1.0); } data(){} }; bool operator < (const data &a,const data &b){ return a.val<b.val; } priority_queue<data>Heap; int a[200005]; double sqr(const double &x){ return x*x; } int T,n,m; int main(){ //freopen("b.in","r",stdin); scanf("%d",&T); for(int zu=1;zu<=T;++zu){ while(!Heap.empty()){ Heap.pop(); } scanf("%d%d",&n,&m); ave=0; for(int i=1;i<=n;++i){ scanf("%d",&a[i]); ave+=(double)a[i]; } ave/=(double)m; double tt=0; for(int i=1;i<=n;++i){ tt+=sqr((double)a[i]-ave); } double ans=tt+sqr(ave)*(double)(m-n); for(int i=1;i<=n;++i){ Heap.push(data((double)a[i],1.0)); } for(int i=1;i<=m-n;++i){ data t=Heap.top(); Heap.pop(); if(t.val<EPS){ break; } Heap.push(data(t.x,t.y+1.0)); ans-=t.val; } printf("Case #%d: %.12f\n",zu,ans/(double)m); } return 0; }