【题解】Rainbow的信号(位运算+概率期望)

本文介绍了一种基于数字信号的解密算法,用于保护Freda与Rainbow之间的通信免受VariantF监听。该算法涉及XOR、AND、OR运算的数学期望值计算,适用于信息安全与算法设计领域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Rainbow的信号

1s,128 MB1s,128\ MB1s,128 MB

【题目描述】

FredaFredaFreda 发明了传呼机之后,rainbowrainbowrainbow 进一步改进了传呼机发送信息所使用的信号。由于现在是数字、信息时代,rainbowrainbowrainbow 发明的信号用 NNN 个自然数表示。为了避免两个人的对话被 大坏蛋 VariantFVariantFVariantF 偷听,rainbowrainbowrainbow 把对话分成 A、B、CA 、B 、CABC 三部分,分别用 a、b、ca、b、cabc 三个密码 加密。现在 FredaFredaFreda 接到了 rainbowrainbowrainbow 的信息,她的首要工作就是解密。FredaFredaFreda 了解到,这三部 分的密码计算方式如下:

1∼N1\sim N1NNNN 个数中,等概率地选取两个数 l、rl、rlr,如果 l>rl>rl>r,则交换 l、rl、rlr。把信号中的第 lll 个数到第 rrr 个数取出来,构成一个数列 PPP

AAA 部分对话的密码是数列 PPPxorxorxor 和的数学期望值。xorxorxor 和就是数列 PPP 中各个数异或之后得到的数; xorxorxor 和的期望就是对于所有可能选取的 l、rl、 rlr,所得到的数列的 xorxorxor 和的平均数。

BBB 部分对话的密码是数列 PPPandandand 和的期望,定义类似于 xorxorxor 和 。

CCC 部分对话的密码是数列 P 的 ororor 和的期望,定义类似于 xorxorxor 和 。

【输入格式】

第一行一个正整数 NNN

第二行 NNN 个自然数,表示 FredaFredaFreda 接到的信号。

【输出格式】

一行三个实数,分别表示 xorxorxor 和、andandand 和、ororor 和的期望,四舍五入保留 333 位小数,相邻两个实数之间用不少于一个空格隔开。三个实数分别占该测试点 40%、30%、30%40\%、30\%、30\%40%30%30% 的分数, 如果你的输出少于三个实数,或者你的输出不合法,将被判 000 分。

【样例输入】

2 
4 5 

【样例输出】

2.750 4.250 4.750 

【样例解释】

包含共四种可能的 l,rl,rl,r

l,rl,rl,rxorxorxorandandandororor
1,11,11,1444444444
1,21,21,2111444555
2,12,12,1111444555
2,22,22,2555555555

以上每一对 l,rl,rl,r 出现的概率相同,因此分别对 xor、and、orxor、and、orxorandor 和取平均数,就是数学期望值。

【数据范围】

对于 20%20\%20% 的数据,1≤N≤1001\le N\le 1001N100

对于 40%40\%40% 的数据,1≤N≤10001\le N\le 10001N1000

对于另外 30%30\%30% 的数据,NNN 个数为 000111

对于 100%100\%100% 的数据,1≤N≤1000001\le N\le 1000001N100000NNN 个自然数均不超过 10910^9109

【算法分析】

对于位运算,最后的结果只和参与运算的当前位的值有关,因此我们可以单独考虑每一位的结果,将每一位对结果的贡献相加,就得到了最后的答案。

1∼n1\sim n1n 转换为二进制,根据题意,转化的二进制不会超过 313131 位,则依次计算 1∼n1\sim n1n 的二进制第 000 位,第 111 位… 第 303030 位进行位运算的值。

for(int i=0;i<31;i++)	//二进制位
    for(int j=1;j<=n;j++)	// n个数的二进制第i位进行位运算
        	//......

l,rl,rl,r 出现的概率相同,因此,l==rl==rl==r 出现的概率为 1n2\frac 1 {n^2}n21l≠rl\neq rl=r 出现的概率为 2n2\frac 2 {n^2}n22

考虑 nnn 个数的第 kkk 位二进制的位运算,设 a[i][j]a[i][j]a[i][j] 表示第 iii 个数二进制的第 jjj 位的值。

andandand 和的期望:

andandand 的特点就是只要出现 000 结果就为 000 ,只有全为 111 时,结果才是 111 。依次计算前 rrr 个数的 andandand 和的期望,同时记录前 rrr 个数中 000 最后一次出现的位置,last[0]=ilast[0]=ilast[0]=i

若第 rrr 个数的第 kkk 位为 a[r][k]=1a[r][k]=1a[r][k]=1 ,以 rrr 为右端点, [l=last[0]+1,r][l=last[0]+1, r][l=last[0]+1,r] 这个区间任意选两个数组成的区间 andandand 运算都是 111 ,则对最后 andandand 和的期望的贡献为:

if(last[0]+1==r) ans_and+=2k×1n2ans\_and+=2^k\times \frac 1 {n^2}ans_and+=2k×n21

if(last[0]+1<r)​ ans_and+=2k×(r−(last[0]+1))×2n2ans\_and+=2^k\times (r-(last[0]+1))\times \frac 2 {n^2}ans_and+=2k×(r(last[0]+1))×n22

若第 rrr 个数的第 kkk 位为 a[r][k]=0a[r][k]=0a[r][k]=0 ,那么不存在 rrr 为右端点的组合使得第 kkk 位二进制进行 andandand 运算结果为 111

ororor 和的期望:

ororor 的特点就是只要有 111 ,最后的结果就是 111 ,只有全为 000 ,结果才是 000 。记录前 rrr 个数中 111 最后一次出现的位置,last[1]=ilast[1]=ilast[1]=i

若第 rrr 个数的第 kkk 位为 a[k][r]=1a[k][r]=1a[k][r]=1,以 rrr 为右端点,前面的所有点都可以和 rrr 组成区间满足区间的数 ororor 运算为 111 ,则对最后 ororor 和的期望的贡献为:

[l,r],l=r[l,r],l=r[l,r],l=r and_or+=2k×1n2and\_or+=2^k\times \frac 1 {n^2}and_or+=2k×n21

[l,r],1≤l<r[l,r],1\le l<r[l,r],1l<r and_or+=2k×(r−1)×2n2and\_or+=2^k\times (r-1)\times \frac 2 {n^2}and_or+=2k×(r1)×n22

若第 rrr 个数的第 kkk 位为 a[r][k]=0a[r][k]=0a[r][k]=0 ,那么 rrr 为右端点,l(1≤l≤last[1])l(1\le l\le last[1])l(1llast[1]) 组成的区间的数 ororor 运算为 111 ,则对最后 ororor 和的期望的贡献为:

and_or+=2k×last[1]×2n2and\_or+=2^k\times last[1]\times \frac 2 {n^2}and_or+=2k×last[1]×n22

xorxorxor 和的期望:

如果 l==r ,设 l xor r=xl\ xor \ r=xl xor r=x 。将 lll 往左扫描,遇到 000 ,区间 [l,r][l,r][l,r]xorxorxor 和不变,遇到 111 ,区间 [l,r][l,r][l,r]xorxorxor 和取反。

如下图,当第 rrr 个数的第 kkk 位为 a[r][k]=0a[r][k]=0a[r][k]=0 时,当 lll 取灰色的位置时,区间 [l,r][l,r][l,r]xorxorxor 和为 111 ,白色的位置时,区间 [l,r][l,r][l,r]xorxorxor 和为 000

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWaEUs2U-1595840188577)(img-GoAlYS9T-1595840156840)

因此,建立两个变量 c1,c2c_1,c_2c1,c2 分别表示第从 r−1r-1r1 倒着往前数的白色区域和灰色区域的长度。

a[r][k]=0a[r][k]=0a[r][k]=0 时,则左端点 lll 只能选择灰色的部分,对最后 xorxorxor 和的贡献的期望为:

ans_xor+=2k×c2×2n2ans\_xor+=2^k\times c_2\times \frac 2 {n^2}ans_xor+=2k×c2×n22

a[r][k]=1a[r][k]=1a[r][k]=1 时,则左端点 lll 只能选择白色的部分,对最后 xorxorxor 和的贡献的期望为:

ans_xor+=2k×c1×2n2ans\_xor+=2^k\times c_1\times \frac 2 {n^2}ans_xor+=2k×c1×n22

同时,需要加上 l==r 的情况,and_xor+=2k×1n2and\_xor+=2^k\times \frac 1 {n^2}and_xor+=2k×n21

rrr 所在的区域一直看作白色,左侧依次为灰色,白色,灰色…

计算 c1,c2c_1,c_2c1,c2 时,当 rrr 增加 111c1++ ,当 a[r][k]=1a[r][k]=1a[r][k]=1c1c1c1 变为灰色区域长度,c2c2c2 变为白色区域长度,交换 swap(c1,c2)swap(c_1,c_2)swap(c1,c2)

总的时间复杂度为 O(kN)O(kN)O(kN)kkk 为二进制位数。

在进行位运算时,可以不用将每个数拆分成二进制,可以直接使用位运算提前二进制下的每一位的值,xxx 的二进制为从有右往左依次为第 000 位,…,提取 xxxkkk 的值:(x>>k)&1

【参考程序】

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],n,last[2];
long double ans_xor,ans_or,ans_and;
void solve()
{
	for(int i=0;i<31;i++)
	{
		last[1]=last[0]=0;
		int c1=0,c2=0;
		for(int j=1;j<=n;j++)
		{
			int t=(a[j]>>i)&1;
			if(t==1)
			{
				ans_or+=(1<<i)*2.0/n/n*(j-1);		
				ans_or+=(1<<i)*1.0/n/n;
				ans_and+=(1<<i)*2.0/n/n*(j-(last[0]+1));
				ans_and+=(1<<i)*1.0/n/n;
				ans_xor+=(1<<i)*2.0/n/n*c1; 
				ans_xor+=(1<<i)*1.0/n/n;
			}
			else 
			{
				ans_or+=(1<<i)*2.0/n/n*last[1];
				ans_xor+=(1<<i)*2.0/n/n*c2;
			}
			last[t]=j;
			c1++;
			if(t==1) swap(c1,c2);
			
		}
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);	
	solve();
	printf("%.3Lf %.3Lf %.3Lf",ans_xor,ans_and,ans_or);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值