CH3801Rainbow的信号

Description

Freda发明了传呼机之后,rainbow进一步改进了传呼机发送信息所使用的信号。由于现在是数字、信息时代,rainbow发明的信号用N个自然数表示。为了避免两个人的对话被大坏蛋VariantF偷听T_T,rainbow把对话分成A、B、C三部分,分别用a、b、c三个密加密码。现在Freda接到了rainbow的信息,她的首要工作就是解密。Freda了解到,这三部分的密码计算方式如下:
在1~N这N个数中,等概率地选取两个数l、r,如果l>r,则交换l、r。把信号中的第l个数到第r个数取出来,构成一个数列P。
A部分对话的密码是数列P的xor和的数学期望值。xor和就是数列P中各个数异或之后得到的数; xor和的期望就是对于所有可能选取的l、r,所得到的数列的xor和的平均数。
B部分对话的密码是数列P的and和的期望,定义类似于xor和。
C部分对话的密码是数列P的or和的期望,定义类似于xor和。
代码改自紫书
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[1000001], b[1000001], n;
double ansxor, ansand, ansor;

inline void solve(int k){
    register int last[2]={0,0},c1=0,c2=0;
    for(register int i=1;i<=n;i++) {//处理b[i]和length=1的情况
        b[i]=((a[i]>>k)&1);//取出每个数的第k位
        if(b[i]){//当且仅当b[i]!=0时才会有贡献
            ansxor+=(1<<k)*1.0/n/n;
            ansand+=(1<<k)*1.0/n/n;
            ansor+=(1<<k)*1.0/n/n;
        }
    }
    for(register int i=1;i<=n;i++){//处理length>=2的情况
        if(b[i]==0){
            ansor+=(1<<k)*2.0/n/n*last[1];
            ansxor+=(1<<k)*2.0/n/n*c2;
        }else{
            ansand+=(1<<k)*2.0/n/n*(i-1-last[0]);//(i-1)-(last[0]+1)+1
            ansor+=(1<<k)*2.0/n/n*(i-1);
            ansxor+=(1<<k)*2.0/n/n*c1;
        }
        c1++;
        if(b[i])swap(c1,c2);
        last[b[i]]=i;
    }
}
int main(){
    cin>>n;
    for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(register int i=0;i<31;i++)solve(i);
    printf("%.3f %.3f %.3f\n",ansxor,ansand,ansor);
}

转载于:https://www.cnblogs.com/lqhsr/p/10808065.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值