【Codeforces 1453D】Checkpoints
题目链接
翻译
每个阶段都有 \(\frac{1}{2}\) 的几率失败,失败了会回到上一个存档点。
想让玩家的期望尝试次数为 \(k\),问你能否设计出一个不超过 \(2000\) 级台阶的策略,满足这个要求。
题解
如果只有一个 \(1\) 的话,那么期望尝试次数为 \(2\)。假设后面出现了一个 \(0\),即 10
,那么到达第 \(2\) 层且通过了第二层(能够到达第三层了)的期望次数
是多少呢? 第一层通过了,次数是 \(2\),然后到达第二层,进行一次尝试。也即 \(2+1=3\)。但是第二层也只有 \(\frac{1}{2}\) 的几率成功。
所以也应该要乘 \(2\),即到达第二层且通过第二层的期望次数为 \(2*(2+1)=6\)。(失败了就要重新从第一层再上)
不难看出,假设 100000...
的长度为 \(i\),设 \(x_i\) 表示 \(i\) 层都通过的期望次数。则 \(x_{i+1}=2*(x_i+1)\) 也即 \(x_i = 2^{i+1}-2\)
并且,只要再出现一个 \(1\) 了,就要重新算期望,即 \(1\) 把不同的段分隔开了。
然后说下构造策略,首先,\(x_i\) 总是一个偶数,所以 \(k\) 为奇数直接 \(-1\)
然后,对于所给的偶数期望 \(k\),我们可以这么玩。会发现 11000..
(注意这里开头有两个连续 \(1\),长度设为 \(i+1\)) 对应的需要重新试的次数为 \(2^{i+1}\),因为加上了第一个 \(1\) 的两次。
只不过这里 \(i>=1\),所以,对于 \(k\ge4\) 的时候,我们只要用 \(11000..\) 这样对应的 \(2^{(i+1)}\) 去减 \(k\) 就好。
因为二进制分解的缘故,我们总能让 \(k\) 对应的二进制中大于等于 \(2^2\) 对应的位都变成 \(0\),因此一直减的结果就是 \(k\) 最后等于 \(2\) 或者 \(0\)。
等于 \(2\) 的时候再补一个 \(1\) 就好啦。
构造出来的层数是 \(1+2+3...log_2K\) 这个数量,不会超过 \(2000\)。
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
vector<int> ans;
int main(){
// freopen("C://1.cppSourceProgram//rush.txt","r",stdin);
ios::sync_with_stdio(0),cin.tie(0);
int T;
cin >> T;
while (T--){
LL k;
cin >> k;
//[1] 特殊判断
if (k % 2 == 1){
cout << -1 << endl;
continue;
}
//[2] 用1(期望值为2, 10000...0(1000..0长度为 i 期望值为2^(i+1)-2
//合在一起就是 2^(i+1), 但是这里 i >= 1
//所以如果k >= 4, 那么就用11000的 batch 减
ans.clear();
while (k >= 4){
ans.push_back(1);
ans.push_back(1);
LL cur = 4;
int i = 1;
while (cur*2 <= k){
cur*=2;
i++;
}
for (int j = 1;j <= i-1; j++){
ans.push_back(0);
}
k -= cur;
}
//k=2或k=0
if (k == 2){
ans.push_back(1);
}
cout << (int)ans.size() << endl;
int len = ans.size();
for (int i = 0;i < len; i++){
cout << ans[i];
if (i == len-1){
cout << endl;
}else{
cout << " ";
}
}
}
return 0;
}