1 条题解

  • 0
    @ 2026-10-27 13:36:01

    思路与算法

    用尾和E[v2(w)]=Σ_{k≥1}Pr(2^k整除w)。令F_s(k,j)为s步后w≡−j (mod2^k)的概率,F_0由初值判定。反推最后一步:加1变成F_{s−1}(k,j+1);倍增只有j偶数可行,变成F_{s−1}(k−1,j/2)。按概率加权,k0恒为1。j最多n,k取到n+31足够,用滚动数组。

    正确性说明

    正整数v2的尾和恒等式成立。加1与倍增的逆同余条件分别如上,两个操作互斥且概率固定,故全概率公式给出准确转移。初始F0为真实整除指示,归纳得全部概率。任一步仅加1或倍增,最终w≤(x+n)2^n<2^(n+30),所以更高整除事件概率0,有限求和精确。

    复杂度

    K=n+31,初始化O(Kn),每层有效j至多n−s+1,时间O(Kn²),滚动空间O(Kn)。n0时直接由初始化求尾和。

    易错点

    本地公开勘误为倍增2x,不能按原笔误x/2产生0。j奇数时倍增分支为0;k0是概率1而非整除运算。p0/p100和n0均合法,输出按1e−6绝对误差比较。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    using D = long double;
    int main() {
        int x, n, p;
        cin >> x >> n >> p;
        int K = n + 31, W = n + 1;
        vector<D> a((K + 1) * W), b(a.size());
        for (int k = 0; k <= K; k++)
            for (int j = 0; j <= n; j++)
                a[k * W + j] = (k == 0 || (k <= 30 && ((x + j) % (1LL << k) == 0)));
        D prob = p / 100.0L;
        for (int s = 1; s <= n; s++) {
            fill(b.begin(), b.end(), 0);
            for (int j = 0; j <= n - s; j++)
                b[j] = 1;
            for (int k = 1; k <= K; k++)
                for (int j = 0; j <= n - s; j++)
                    b[k * W + j] = (1 - prob) * a[k * W + j + 1] +
                                   (j % 2 == 0 ? prob * a[(k - 1) * W + j / 2] : 0);
            a.swap(b);
        }
        D ans = 0;
        for (int k = 1; k <= K; k++)
            ans += a[k * W];
        cout << fixed << setprecision(10) << ans << '\n';
    }
    
    • 1

    信息

    ID
    2120
    时间
    1000ms
    内存
    512MiB
    难度
    提高
    标签
    递交数
    0
    已通过
    0
    上传者