zl程序教程

您现在的位置是:首页 >  其它

当前栏目

【Codeforces 1453D】Checkpoints

Codeforces
2023-09-14 09:03:41 时间

题目链接

链接

翻译

每个阶段都有 \(\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;
}