1 条题解

  • 0
    @ 2025-8-24 23:08:04

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 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}}$ 是单调递减的,显然只有取到 ui2k\frac{u_i}{2^k} 后,才能取到 ui2k+1\frac{u_i}{2^{k+1}}。因此,可以维护一个大顶堆,初始时将每个社团的权值都放入堆中。

    枚举每个格子,每次从大顶堆中取出权值最大的社团,将该格子分配给该社团,并将其权值减半后重新放回堆中。这种方法的时间复杂度为 O(HlogT)O(H \log T),还可能因浮点运算产生精度问题,无法通过此题。

    考虑优化,注意到任意权值 uiu_i 都可以表示为 ai×2nia_i \times 2^{n_i},其中 1ai<21 \leq a_i < 2niNn_i \in \mathbb{N}。当大顶堆中堆顶元素小于 22 时,堆内所有元素均位于区间 [1,2)[1, 2)

    此时有个很好的性质,即对于任意 ai<aj,kNa_i < a_j,k\in\mathbb{N},满足:

    $$\frac{a_i}{2^{k+1}} < \frac{a_j}{2^{k+1}} < \frac{a_i}{2^k} < \frac{a_j}{2^k} $$

    设还剩 hh 个待分配的格子,每个社团会先被分配 hT\left\lfloor \frac{h}{T} \right\rfloor 个格子,剩下的 hmodTh \bmod T 个格子将优先分配给权值 aia_i 最大的 hmodTh \bmod T 个社团。

    显然,对于每个 uiu_i,其 niloguin_i \sim \log u_i,因此时间复杂度 O(Tlogui)O(T \log u_i)

    参考代码

    #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
    上传者