题解 CF1348D 【Phoenix and Science】

题目大意,每天细菌会在早上选择分裂,晚上生长。

观察题目,我们可以发现。不管我们怎么分裂细菌,这一天晚上的总质量都是前一天晚上的总质量加上今天的细菌数。

那么我们肯定希望细菌分裂的越多越好,这样我们减少后几天的压力。所以前几天我们尽可能的让所有细菌都分裂。

如果把初始算成第零天,那么前 \(i\) 天如果细菌全部分裂就有 \(((1<<i)-1)\) 质量,第 \(i\) 天的细菌总数是 \((1<<(i-1))\)

所以如果 \(N\) 小于 \(((1<<i)-1+1<<(i-1))\) ,是肯定不行的。因为后几天细菌总质量会直接超过 \(N\)

如果 \(N\) 大于等于 \(((1<<i)-1+1<<(i-1))\) ,就可以实现在某一天质量正好到 \(N\)

然后就是处理后几天的问题了,通过手玩可以发现要么需要一天时间,要么就两天。用一个 \(if\) 语句判断一下就行了。

代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define INF 1LL<<62;
#define ll long long
#define For(X,From,To) for(ll X=From;X<=To;X++)
using namespace std;
ll T,N,Cnt[100],Num;
ll QP(ll B,ll K,ll Mod){ ll Ans=1;for(;K;K>>=1,B=B*B%Mod) if(K&1) Ans=Ans*B%Mod;return Ans;}
template<class T>void Read(T &X){
	X=0;ll F=0;char Ch=getchar();
	while(Ch<'0' || Ch>'9'){ F|=(Ch=='-');Ch=getchar();}
	while(Ch>='0' && Ch<='9'){ X=X*10+(Ch^48);Ch=getchar();}
	X=F? -X:X;
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	Read(T);
	while(T--){
		Read(N);
		Num=0;
		memset(Cnt,0,sizeof(Cnt));
		for(ll i=32;i>=1;i--)
		if(N>=(1LL<<i)-1+(1LL<<(i-1))){
			for(ll j=1;j<i;j++){
				Num++;
				Cnt[Num]=1LL<<(j-1);
			}
			N=N-((1LL<<i)-1);
			if(N>0){
				if((1LL<<i)>=N){
					Num++;
					Cnt[Num]=N-(1LL<<(i-1));
				}else{
					Num++;
					Cnt[Num]=N/2-(1LL<<(i-1));
					Num++;
					Cnt[Num]=N%2;
				}
			}
			printf("%lld\n",Num);
			for(ll j=1;j<=Num;j++) printf("%lld ",Cnt[j]);
			printf("\n");
			break;
		}
	}
	return 0;
}qwq
posted @ 2020-05-14 15:00  eromangasensei  阅读(204)  评论(0编辑  收藏  举报