【luogu P3898】期望异或 / T3 / 大新闻(数位DP)(数学)

期望异或 / T3 / 大新闻

题目链接:luogu P3898

题目大意

有一个数,等概率选 0~n-1 里面的整数。
然后又 p 的概率可以知道这个数,然后选择 0~n-1 中一个异或它最大的数。
否则就是等概率选 0~n-1 里面的整数。
问你这两个数的异或值的期望值是什么。

思路

不难看出 p roll 出的两种情况我们可以分别讨论,然后再按概率乘起来加起来。

那首先不知道:
考虑枚举每一位看贡献的值:
那我们设 fifi1 的概率,那就有 2i+1fi(1fi)
接着考虑如何求 fi

我们不难想到可以把位数相同且不会超过 n 一起讨论。
02k11 的这一位都是 02k12k1 都是 1
然后 x2k+2k1(x+1)2k 都是 1
那不难想到整段的就是 n2k+12k,剩下一段可能有,可能没有。
有的话就是 nmod2k+12k,没有的话这个值会小于 0,那就直接 max{nmod2k+12k,0}
总的来说,就是:
fk=n2k+12k+max{nmod2k+12k,0}n

接着考虑求知道的。(这题最阴间的部分)
也是同样的,考虑看每一位是否有 1。(而且我们要看的是 0n1,就直接把 n 减一)
如果是 1,那也是就说,它可以选 0,后面的就可以任意选,那后面一定可以匹配出 1
那就直接是贡献乘个数,直接就是 2k(n+1)
如果是 0,那你要是 1 才可以,就要前面没有搞满,你考虑统计有多少个搞满的,然后减去就是没有搞满的。(最后还要减去当前位选 0 的)
那你搞完这里之后,这里就是一个搞满的,那就要统计搞满的就要加上 2k

接着再回来看 1 的时候统计搞满的要怎么变。
那你这个时候你可以选 1 也可以选 0,一种是搞满的一种是搞不满的。
那就是一半一半的概率,那原来可以搞满的就有一半不能搞满,就要除二。

然后就可以了。

代码

#include<cstdio> #include<iostream> #define ll long long using namespace std; ll n, nn; long double p, eps = 1e-7; long double ans, an0, an1; long double pp[71]; int b; void work0() { for (int i = 0; i < nn; i++) { pp[i] = 1.0 * (n / (1ll << (i + 1))) * (1ll << i);//前面那些整段的 pp[i] += 1.0 * max(n % (1ll << (i + 1)) - (1ll << i), 0ll);//最后一段,注意可能会没有 pp[i] = pp[i] / (1.0 * n); } for (int i = 0; i < nn; i++) { an0 = an0 + 1.0 * (1ll << (i + 1)) * pp[i] * (1.0 - pp[i]);//有的概率乘没有的概率乘贡献 } } void work1() { n--; nn = 0; ll tmp = n; while (tmp) { tmp >>= 1; nn++; } ll num1 = 0;//记录有多少个数不能在前面搞出 1 for (int i = nn - 1; i >= 0; i--) { if ((n >> i) & 1) { an1 = an1 + 1.0 * (1ll << i) * (n + 1ll); num1 >>= 1; } else { an1 = an1 + 1.0 * (1ll << i) * (n + 1ll - (1ll << i) - (num1 >> 1)); num1 += (1ll << i); } } n++; nn = 0; tmp = n; while (tmp) { tmp >>= 1; nn++; } an1 = an1 / (1.0 * n); } int main() { scanf("%lld %LF", &n, &p); ll tmp = n; while (tmp) { tmp >>= 1; nn++; } work0(); work1(); ans = an0 * (1.0 - p) + an1 * p; //如果是 jzoj 就是注释掉的这一段 // while (ans - 10.0 >= eps) { // b++; // ans = ans / 10.0; // } // while (ans > eps && ans < 1) { // b--; // ans = ans * 10.0; // } // // printf("%.8LF %d", ans, b); printf("%.8LF", ans); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P3898.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(60)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示