题解:P10500 Rainbow的信号

· · 题解

P10500 Rainbow的信号

谢谢管理大大的审核,

顺便无耻的推一下 blog。

思路

因为位运算当前位的结果只与当前位有关,所以可以单独考虑每一位,最后将每一位的贡献相加就是答案。

由于 lr 是等概率选取,所以选取长度为 1 的区间(l = r)的概率是 \frac{1}{n^2},选取其他区间(l \neq r)的概率是 \frac{2}{n^2}

a_i,a_j 表示第 i 个数字的第 j 个二进制位的值;last[k] (k=0,1) 表示 k 最后出现的位置。

分别讨论三种运算的期望:

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Elaina 0
const int N=100010;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}

int n,a[N];
int last[3],c1,c2;
double ansand,ansor,ansxor;

main(){
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();

    for(int i=0;i<=30;i++){
        last[0]=last[1]=0;
        c1=c2=0;
        for(int j=1;j<=n;j++){
            int now=(a[j]>>i)&1;
            double ret=(double)(1<<i)/(n*n);
            if(now){
                ansand+=ret+2.0*ret*(j-(last[0]+1));
                ansor+=ret+2.0*ret*(j-1);
                ansxor+=ret+2.0*ret*c1;
            }else{
                ansor+=2.0*ret*last[1];
                ansxor+=2.0*ret*c2;
            }
            last[now]=j;
            c1++;
            if(now) swap(c1,c2);
        }
    }

    printf("%.3lf %.3lf %.3lf",ansxor,ansand,ansor);
    return Elaina;
}