1 条题解

  • 0
    @ 2025-8-24 22:58:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Elaina_0
    今朝依旧,今后亦然。

    搬运于2025-08-24 22:58:36,当前版本为作者最后更新于2024-05-24 17:01:11,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P10500 Rainbow的信号

    谢谢管理大大的审核,

    顺便无耻的推一下 blog

    思路

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

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

    ai,aja_i,a_j 表示第 ii 个数字的第 jj 个二进制位的值;last[k](k=0,1)last[k] (k=0,1) 表示 kk 最后出现的位置。

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

    • and\operatorname{and} 的期望

      • 若第 xx 个数字的第 kk 位是 11,以 xx 为右端点,在 [last[0]+1,r][last[0]+1,r] 区间内任取两个数组成的区间 and\operatorname{and} 和都是 11,因此她的贡献为:

        $$\begin{cases} last[0] = x  2^k \times \frac{1}{n^2}\\ last[0]+1 \neq x 2^k \times (x-(last[0]+1)) \times \frac{2}{n^2} \end{cases}$$
      • 若第 xx 个数字的第 kk 为是 00,不存在左端点与 xx 的组合使得区间的 and\operatorname{and} 和为 11

    • or\operatorname{or} 的期望

      • 若第 xx 个数字的第 kk 位是 11,前面所有点都可以与 xx 组成区间使得 or\operatorname{or} 和为 11,所以她的贡献为:

        $$\begin{cases} l = x 2^k \times \frac{1}{n^2}\\ l \neq x 2^k \times (x−1) \times \frac{2}{n^2} \end{cases}$$
        • 若第 xx 个数字的第 kk 位是 00,以 xx 为右端点,last[1]≤last[1] 的数字可以选作左端点,所以她的贡献为:
        2k×last[1]×2n22^k \times last[1] \times \frac{2}{n^2}
    • xor\operatorname{xor} 的期望

      tt[l,x][l,x] 区间的 xor\operatorname{xor} 和, c1c1 表示 [l,x][l,x] 区间 xor\operatorname{xor} 和为 00ll 个数,c2c2 表示 [l,x][l,x] 区间 xor\operatorname{xor} 和为 11ll 个数。

      l=xl = x 开始,将 ll 向左移动,若第 ll 位是 11tt 取反,否则 tt 不变。

      • 若第 xx 个数字的第 kk 位是 11,则 ll 只能选择 c1c1 表示的部分,所以她的贡献为:

        2k×c1×2n22^k \times c1 \times \frac{2}{n^2}
      • 若第 xx 个数字的第 kk 位是 00,则 ll 只能选择 c2c2 表示的部分,所以她的贡献为:

        2k×c2×2n22^k \times c2 \times \frac{2}{n^2}

        最后还要加上 l=xl = x 的贡献:

        2k×1n22^k \times \frac{1}{n^2}

        当右端点 rr 增加 11,令 c1c1 增加 11

        a[r]=1a[r] = 1,则还需交换 c1,c2c1,c2

    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;
    }
    
    • 1

    信息

    ID
    10178
    时间
    1000ms
    内存
    512MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者