Codeforces 1348D - Phoenix and Science (贪心)


题面

Prob




题意

最开始存在一个重量为 1 的细菌

每个晚上可以选择一些或全部的细菌进行分裂,数量一分为二,总重量不变(也可以不选)

然后每个细菌重量 +1

问能否使得这群细菌在某些天数后总重量等于 n

能,则输出最少天数和每晚进行分裂的数量

不能,输出 -1




解题思路

如果细菌一直不分裂,则 n-1 天后质量即为 n ,又因为 2<=n<=109 ,所以不存在 -1 的情况

如果在某一天细菌的数量为 t ,则参与分裂的数量最多也只能是 t,即每晚分裂后能得到的最大数量为 2t

可以得到总重量的迭代公式就是 后一天重量=前一天重量+当天分裂后细菌的数量

所以关于 细菌数量 t 的数组一定满足 t[ i-1 ] <= t[ i ] <= 2 * t[ i-1 ]

根据指数函数模型,贪心可得,前期应当尽可能让细菌全部分裂,才能让总数量快速上升

即数组 t 先按照 1 2 4 8 16 32 ... 的数量递增,且保证这些数字的和不大于题目给定的 n

最后再把 n-sum{1,2,4,8,16,...} 加入到这个数组中,排序后即为最优解(如果为 0 无需插入)


例,如果题目给定 n = 75 ,先得到细菌数量为 1,2,4,8,16,32 ,发现接下来的 64 加入后总和会大于 n

此时还差细菌数量为 n-sum = 75-(1+2+4+8+16+32) = 11 的一天

所以插入后得到 1,2,4,8,11,16,32 ,即为每天存在的细菌数量

最后根据差值输出,即为每晚要分裂的个数




程序

#include<bits/stdc++.h>
using namespace std;

void solve()
{
    int n,tmp=1,sum=0;
    vector<int> t;
    cin>>n;
    
    while(sum+tmp<=n)
    {
        t.push_back(tmp);
        sum+=tmp;
        tmp<<=1; // 2的指数级别增长
    }
    if(sum<n) //如果最后还有差值
    {
        t.push_back(n-sum);
        sort(t.begin(),t.end()); //插入后排序
    }
    
    int siz=t.size();
    cout<<siz-1<<'\n';
    for(int i=1;i<siz;i++)
        cout<<t[i]-t[i-1]<<' '; //根据差值输出作为答案
    cout<<'\n';
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--)
        solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/stelayuri/p/12819544.html