嘘~ 正在从服务器偷取页面 . . .

CF441E Valera and Number 题解


CF441E Valera and Number 题解

题目链接:CF441E Valera and Number

题意

给出一个数 $x$,对它进行 $k$ 次操作,每次操作:

  • 以 $p \%$ 的概率对它乘以 $2$。
  • 以 $(100 - p) \%$ 的概率对它加上 $1$。

求该数最终二进制下末尾 $0$ 个数的期望。

输入格式

The first line of the input contains three integers $x,k,p(1\le x\le 10^{9}, 1\le k\le 200, 0\le p\le 100)$ .

输出格式

Print the required expected value. Your answer will be considered correct if the absolute or relative error doesn’t exceed $10^{-6}$ .

设 $f_{i,j}$ 表示 $x$ 经过执行过 $i$ 次后, $x+j$ 的期望答案,则

最后答案就是 $f_{k,0}$ 。说实话这个转移的前一部分还是有点晕的,我想了好一会。

分析下复杂度。考虑 dp 中一条贡献路径的 $j$ ,显然贡献的过程会使 $j$ 乘 $2$ 或者加 $1$ 。

而当 $j > k$ 时,减 $1$ 操作是不可能使得 $j=0$ 的,因为至多 $k$ 次操作,因此这样的 $j$ 对答案没有贡献

综上,时间复杂度 $\mathcal{O}(k^2)$

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(555))

int x,k,t;
double p,q,f[N][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cout << fixed << setprecision(15);
    cin >> x >> k >> t; p = t * 0.01; q = 1.0 - p;
    for(int j = 0; j <= k; j++) f[0][j] = (double)(__builtin_ctz(x + j));
    for(int i = 1; i <= k; i++)
        for(int j = 0; j <= k; j++)
        {
            f[i][j] += f[i - 1][j + 1] * q;
            f[i][j << 1] += (f[i - 1][j] + 1) * p;
        }
    cout << f[k][0] << '\n';
    return 0;
}

参考文献

[1] https://yhx-12243.github.io/OI-transit/records/cf441E.html

[2] https://www.luogu.com.cn/blog/dowhiletrue/solution-cf441e


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录