【luogu 3898】大新闻(数位 DP)

文章目录

题意

**记者弄了个大新闻,这个新闻是一个在 [0,n) 内等概率随机选择的整数,记其为 x。为了尽可能消除这个大新闻对公众造成的不良印象,我们需要在 [0,n)内找到某一个整数 y,使得 x ⊕ y 达到最大值。这里 ⊕ 代表异或。

问题在于,**记者有可能对大新闻进行了加密。情报显示,大新闻没有被加密的概率为 p。我们决定采取这样的策略:如果大新闻没有被加密,那么我们选出使得 x ⊕ y 最大的 y;否则,我们在 [0,n) 内等概率随机选择一个整数作为 y。

请求出 x ⊕ y 的期望值。

思路

对于两个问题分开求解。

第一个问题求的是

∑ i = 0 n − 1 ∑ j = 0 n − 1 i    x o r    j \sum_{i=0}^{n-1}\sum_{j=0}^{n-1}i \; xor\; j i=0n1j=0n1ixorj

考虑对于每一位求贡献。某一位的贡献就是该位为 0 的个数和该位为 1 的个数相乘再乘两倍。

第二个问题求的是

∑ i = 0 n − 1 max ⁡ j = 0 n − 1 i    x o r    j \sum_{i=0}^{n-1}\max_{j=0}^{n-1}i \; xor\; j i=0n1j=0maxn1ixorj

可以用数位 DP 求解。对于某一位 k k k,假如 n − 1 n-1 n1 k k k 位是 1 ,那么第 k k k 位是 1 的 i i i 对应的 j j j 在第 k k k 位上就要选 0 ,这个 j j j 就脱离上界限制了,后面的贡献就是 2 k + 1 − 1 2^{k+1}-1 2k+11 。否则的话,一直不能脱离限制,就一直算每一位的贡献。

这道题卡精度,说好的相对误差 1 0 − 5 10^{-5} 105 被搞成了绝对误差。建议口胡过去就算了。

代码

//bzoj 3652
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long LL;
const int E = 60;
LL n;
double p, ans1, ans2;

void dfs(int now, LL cnt, bool lim){
	if (now < 0) return;
	if (!lim){
		double pp = double(cnt)/double(n);
		ans2 += pp*((1LL<<now+1)-1);
		return;
	}
	if ((n-1>>now)&1){
		LL cnt0 = (cnt>>now+1<<now)+min(cnt&((1LL<<now+1)-1), (1LL<<now));
		LL cnt1 = cnt-cnt0;
		double pp = double(cnt)/double(n);
		ans2 += pp*(1ll<<now);
		dfs(now-1, cnt0, 1);
		dfs(now-1, cnt1, 0);
	}
	else{
		LL cnt0 = (cnt>>now+1<<now)+min(cnt&((1LL<<now+1)-1), (1LL<<now));
		LL cnt1 = cnt-cnt0;
		double pp = double(cnt1)/double(n);
		ans2 += pp*(1ll<<now);
		dfs(now-1, cnt, 1);
	}
}

signed main()
{
	scanf("%lld%lf", &n, &p);
	ans1 = ans2 = 0;
	for (int i = E; i >= 0; -- i){
		LL cnt0 = (n>>i+1<<i)+min(n&((1LL<<i+1)-1), (1LL<<i));
		LL cnt1 = n-cnt0;
		double pp = double(cnt1)/double(n);
		ans1 += (1.0-pp)*(1LL<<i)*pp;
	}
	ans1 *= 2.0;
	dfs(E, n, 1);
	printf("%.6f\n", ans1*(1.0-p)+ans2*p);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值