Scapegoat Gym - 101775B (贪心+推公式)

题目链接https://vjudge.csgrandeur.cn/problem/Gym-101775B
原文

题意:

现在某人闯祸了,产生了 N 个锅,每个锅有个严重点数,现在可以安排 M 个替罪羊去背锅。

每个替罪羊最多只能背一个锅。若一只羊背一个锅,则该锅的严重点数全部算在它头上;若多只羊背同一个锅,则每个羊分到该锅的一部分的严重点数。

现在考虑一种安排方案,使得所有的身上的严重点数的方差最小。

题解

先考虑上 N 只羊一一对应地背 N 个锅,剩下 M−N 个替罪羊身上严重点数均为 0,当然这样并不是最优解。

应当把再剩下 M−N 个替罪羊安排进 N 个锅里分摊责任,使得方差减小。考虑贪心的思路,每次安排进去一只羊,都要使得方差减小最多。

考虑将新来的羊安排到某个任务,该任务严重点数为 a[i],且原来的背锅羊数是 num,那么首先每个替罪羊分到的严重点数的平均数肯定是不变的
\(\overline{X} = \frac{a[1]+ a[2]+ \cdots + a[n]}{m}\),因此它原本对方差的贡献为\(\frac{1}{m} \cdot num \cdot (\frac{a[i]}{num}-\overline{X})^2\)

而现在新加进去一个替罪羊,这个任务对方差的新的贡献为 \(\frac{1}{m} \cdot (num+1) \cdot (\frac{a[i]}{num+1}-\overline{X})^2\)
显然,方差的差值就是\(\Delta = num \cdot (\frac{a[i]}{num}-\overline{X})^2 -(num+1) \cdot (\frac{a[i]}{num+1}-\overline{X})^2 = \frac{a[i]^2}{num \cdot (num+1)} - \overline{X}^2\)

因为平均数不变,因此我们让每次挑一个任务让它的$ \frac{a[i]^2}{num \cdot (num+1)}$最大就好了,这个可以用优先队列。

因此代码整体思路就是:

  • 存储替罪羊的数量:num。
  • 将节点放入优先队列,按照$ \frac{a[i]^2}{num \cdot (num+1)}$排序
  • 利用num求出每个锅对方差的贡献,相加

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int N=5e5+10;
// const double eps=1e-10;
struct node{
    int id, num,a;
    double get() const{
        return a*a*1.0/num/(num+1);
    }
    bool operator<(const node &t) const {
        return t.get()>this->get();
    }
};

signed main()
{
    int t;cin>>t;
    int Case=1;
    while(t--){
        priority_queue<node> q;
        int n,m;
        scanf("%lld %lld",&n,&m);
        double aver=0;
        for(int i=1;i<=n;i++){
            int x;
            scanf("%lld",&x);
            aver+=x;
            q.push({i,1,x});
        }
        aver/=m;
        for(int i=0;i<m-n;i++){
            node x=q.top();q.pop();
            x.num+=1;
            q.push(x);
        }
        double ans=0;
        while(q.size()){
            node x=q.top();q.pop();
            ans+=x.num*(x.a*1.0/x.num-aver)*(x.a*1.0/x.num-aver);
        }
        ans/=m;
        printf("Case #%lld: %.12lf\n",Case++,ans);
    }

    return 0;
}

posted @ 2022-10-22 11:31  kingwzun  阅读(30)  评论(0编辑  收藏  举报