Scapegoat Gym - 101775B (贪心+推公式)
题目链接https://vjudge.csgrandeur.cn/problem/Gym-101775B
原文
题意:
现在某人闯祸了,产生了 N 个锅,每个锅有个严重点数,现在可以安排 M 个替罪羊去背锅。
每个替罪羊最多只能背一个锅。若一只羊背一个锅,则该锅的严重点数全部算在它头上;若多只羊背同一个锅,则每个羊分到该锅的一部分的严重点数。
现在考虑一种安排方案,使得所有的身上的严重点数的方差最小。
题解
先考虑上 N 只羊一一对应地背 N 个锅,剩下 M−N 个替罪羊身上严重点数均为 0,当然这样并不是最优解。
应当把再剩下 M−N 个替罪羊安排进 N 个锅里分摊责任,使得方差减小。考虑贪心的思路,每次安排进去一只羊,都要使得方差减小最多。
考虑将新来的羊安排到某个任务,该任务严重点数为 a[i],且原来的背锅羊数是 num,那么首先每个替罪羊分到的严重点数的平均数肯定是不变的
,因此它原本对方差的贡献为。
而现在新加进去一个替罪羊,这个任务对方差的新的贡献为
显然,方差的差值就是
因为平均数不变,因此我们让每次挑一个任务让它的最大就好了,这个可以用优先队列。
因此代码整体思路就是:
- 存储替罪羊的数量:num。
- 将节点放入优先队列,按照排序
- 利用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; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16815694.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
标签:
,
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步