版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luyehao1/article/details/83861394
题目链接:
题意:
有n个问题,有m个人来背锅,每个问题至少要有一人背锅。每个问题有权值a[i],若k个人同时为第i个问题背锅,那么每个人的压力是a[i]/k。现在让你分配几个人为第几个问题背锅,使得每个人压力的方差最小。
方差定义:。
思路:
因为每个问题至少要有一人背锅,所以只要考虑剩下的m-n个人即可。因为要让方差尽可能小,所以我们需要让每次一个人产生的贡献尽可能大。所以每次让一个人为他加入前后方差之差最大的那个问题背锅就是最优的。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+10;
typedef struct node{
int id;
double cnt;
double val;
bool operator < (const node &num) const {
if(val==num.val){
return cnt<num.cnt;
}
return val<num.val;
}
}Point;
int n,m;
double a[MAX];
double avg;
priority_queue<Point>q;
int mp[MAX];
int main()
{
int T;
scanf("%d",&T);
int Case=1;
while(T--)
{
while(!q.empty()) q.pop();
scanf("%d%d",&n,&m);
avg=0;
for(int i=0;i<n;i++){
scanf("%lf",&a[i]);
mp[i]=1;
avg+=a[i];
}
avg/=(double)m;
for(int i=0;i<n;i++){
double x = mp[i]*(a[i]/mp[i]-avg)*(a[i]/mp[i]-avg)-(mp[i]+1)*(a[i]/(mp[i]+1)-avg)*(a[i]/(mp[i]+1)-avg);
q.push(Point{i,mp[i],x});
}
for(int i=0;i<m-n;i++){
Point now = q.top();
q.pop();
mp[now.id]++;
double x = mp[now.id]*(a[now.id]/mp[now.id]-avg)*(a[now.id]/mp[now.id]-avg)-(mp[now.id]+1)*(a[now.id]/(mp[now.id]+1)-avg)*(a[now.id]/(mp[now.id]+1)-avg);
q.push(Point{now.id,mp[now.id],x});
}
double ans=0;
for(int i=0;i<n;i++){
ans+=1.0*mp[i]*(a[i]/mp[i]-avg)*(a[i]/mp[i]-avg);
}
ans/=(double)m;
printf("Case #%d: %.12lf\n",Case++,ans);
}
return 0;
}