216. Rainbow的信号(数学期望)

 

216. Rainbow的信号 - AcWing题库

1.题意

给出一组数,求所有连续子区间xor,or,and和的平均值。

对于区间端点,任意等概率的取:

l!=r,有两次情况会被取到;l==r,只有一次情况会被取到。

共有n*n种情况;

2.思路

因为是xor,or,and这三种运算,都是位运算,二进制每个位置上的情况是独立的,所以考虑求二进制各个位置上对答案的贡献。

对于右端点r,数是a[r],枚举他的二进制上每一位,下面讨论的是第k位上的值v。

如果一段区间(l,r)在第k位上对答案有贡献:

l!=r 2^(k+1)/(n*n); 

l=r   2^(k)/(n*n);

xor:

一段区间[l,r]只有在k位上有奇数个1时对答案有贡献;

如果有偶数个1时,对答案的贡献为0;

所以我设z[k]为【[1,r],r】中有多少个区间是奇数个1;

当v=1时,z[k]=r-z[k],对答案的贡献是((z[k]-1)*(2^(k+1))+2^k)/(n*n);

当v=0时,z[k]=z[k],对答案贡献是2*(k+1)*z[k]/(n*n);

and:

一段区间只有在第k位上是全为1,才对答案有贡献;

所以我用下x[k]记录当前最后一次出现0的位置;

当v=1,x[k]=x[k],对答案贡献为((r-x[k]-1)*2^(k+1)+2^k)/(n*n);

当v=0,x[k]=r,对答案贡献为0;

or:

一段区间只要有一个1时,就对答案有贡献;

所以我记录最后一次出现1的位置;

v=1,y[k]=r,对答案贡献((y[k]-1)*2^(k+1)+2^k)/n*n;

v=0,y[k]=y[k],对答案贡献y[k]*2^(k+1)/n*n;

3.代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long 
const int N=1e5+100;
const int MAX=1e9;
long double sum1,sum2,sum3;
LL x[33],y[33],z[33],a[N];
LL  n;
int main(){
   cin>>n;
   for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
   for(int r=1;r<=n;r++)
       for(int k=0;k<31;k++)
       {   int v=(a[r]>>k)&1;
           if(v){
           z[k]=r-z[k];
        sum1+=1.0*((1<<k)+(z[k]-1)*(1<<(k+1)))/(n*n);           
           sum2+=1.0*((r-x[k]-1)*(1<<(k+1))+(1<<k))/(n*n);
        y[k]=r;
        sum3+=1.0*((y[k]-1)*(1<<(k+1))+(1<<k))/(n*n);                    
       }
       else{
           sum1+=1.0*z[k]*(1<<(k+1))/(n*n);
         x[k]=r;
         sum3+=1.0*(y[k])*(1<<(k+1))/(n*n);      
       }
    }
    printf("%.3Lf %.3Lf %.3Lf\n",sum1,sum2,sum3);
    return 0;
}
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值