传送门
题意
小P觉得很无聊于是开始繁殖细菌。
在第一天,有一个质量为1的细菌。
接下来的每一天,会有若干个细菌分裂成两个,两个细菌的质量皆为原来细菌的一半。
所有细菌分裂完之后每个细菌的质量增长1。
给出你一个整数
n
n
n如果没有方案能够在若干天后使得细菌质量的和等于
n
n
n,输出
−
1
-1
−1,否则输出两行,第一行是最少花费的天数,第二行是每一天分裂的细菌的数量。
分析
我们可以推一下在每天完全分裂的情况下,达到
n
n
n个细胞所用的时间
第一天为1
第二天为3
第三天为7
第
x
x
x天为
2
x
−
1
2 ^ x - 1
2x−1
所以,我们可以求出来天数为
l
o
g
(
n
)
log(n)
log(n)
然后我们怎么去构造呢,我们假设第
i
i
i天分裂一个细胞,那么他对答案的贡献就是
(
d
−
i
+
1
)
(d - i + 1)
(d−i+1),不难发现从第1天到第
d
d
d天,每个细胞分裂所产生的贡献越来越小,所以我们可以在一开始,尽量让细胞多分裂,然后在接近
n
n
n的时候,去控制它的分裂速度
代码
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
const ll mod = 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a) {
char c = getchar(); T x = 0, f = 1; while (!isdigit(c)) {if (c == '-')f = -1; c = getchar();}
while (isdigit(c)) {x = (x << 1) + (x << 3) + c - '0'; c = getchar();} a = f * x;
}
int gcd(int a, int b) {return (b > 0) ? gcd(b, a % b) : a;}
int main() {
int T;
read(T);
while(T--){
ll n;
read(n);
ll d = 0,sum = 0,p = 1;
while(sum < n){
sum += p;
p <<= 1;
d++;
}
d--;
vector<ll> v;
n = n - 1 - d;
sum = 1;
for(ll i = d;i;i--){
p = min(n / i,sum);
v.pb(p);
n -= p * i;
sum += p;
}
if(n != 0){
puts("-1");
continue;
}
dl(d);
for(int i = 0;i < d;i++) printf("%d ",v[i]);
puts("");
}
return 0;
}