1 条题解
-
0
自动搬运
来自洛谷,原作者为

lailai0916
Student & Developer搬运于
2025-08-24 23:08:04,当前版本为作者最后更新于2024-12-15 16:57:22,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
原题链接
解题思路
序列 $u_i, \frac{u_i}{2}, \frac{u_i}{4}, \cdots, \frac{u_i}{2^{H-1}}$ 是单调递减的,显然只有取到 后,才能取到 。因此,可以维护一个大顶堆,初始时将每个社团的权值都放入堆中。
枚举每个格子,每次从大顶堆中取出权值最大的社团,将该格子分配给该社团,并将其权值减半后重新放回堆中。这种方法的时间复杂度为 ,还可能因浮点运算产生精度问题,无法通过此题。
考虑优化,注意到任意权值 都可以表示为 ,其中 且 。当大顶堆中堆顶元素小于 时,堆内所有元素均位于区间 。
此时有个很好的性质,即对于任意 ,满足:
$$\frac{a_i}{2^{k+1}} < \frac{a_j}{2^{k+1}} < \frac{a_i}{2^k} < \frac{a_j}{2^k} $$设还剩 个待分配的格子,每个社团会先被分配 个格子,剩下的 个格子将优先分配给权值 最大的 个社团。
显然,对于每个 ,其 ,因此时间复杂度 。
参考代码
#include <bits/stdc++.h> using namespace std; using ll=long long; const int N=100005; struct Node { int id,cnt; double val,st; bool operator<(const Node &rhs) const { if(val!=rhs.val)return val<rhs.val; if(cnt==0^rhs.cnt==0)return cnt; if(st!=rhs.st)return st<rhs.st; return id>rhs.id; } }a[N]; int ans[N]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n,k; cin>>n>>k; priority_queue<Node> q; for(int i=1;i<=n;i++) { double x; cin>>x; q.push({i,0,x,x}); } while(!q.empty()&&k) { Node u=q.top(); if(u.val<2)break; q.pop(); u.cnt++; u.val/=2; q.push(u); k--; } while(!q.empty()) { Node u=q.top(); q.pop(); a[u.id]=u; } sort(a+1,a+n+1); for(int i=1;i<=n;i++) { ans[a[i].id]=a[i].cnt+k/n+(i>n-k%n); } for(int i=1;i<=n;i++) { cout<<ans[i]<<' '; } return 0; }
- 1
信息
- ID
- 11308
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者