题面
题意
最开始存在一个重量为 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;
}