• joyoi2020/lfyzoj114 Rainbow 的信号


    位与位间互不影响。一位一位计算。

    长度为 (1) 的区间,选出概率为 (1/n^2)。其余区间,选出概率为 (2/n^2)。(这里的区间 (l leq r)

    枚举右端点。记 (last_0) 表示 (0) 上一次出现的位置。 (last_1) 同样。

    下面我们只研究区间长度不为 (1) 的。为 (1) 的话直接计上就好了。

    对于 (mathrm{and}) 和,倘若当前数的这一位为 (0) 则不用计算,否则,左端点在 ([last_0+1,now-1]) 间的区间都是合法的,答案累计 (2 imes 2^k imes (now-last_0-1) /n^2)(now) 是当前在枚举哪个右端点,(k) 是当前在枚举 (a_{now}) 的二进制第 (k) 位。

    对于 (mathrm{or}) 和,倘若当前数的这一位为 (1) 则左端点在 ([1,now-1]) 的区间都合法,否则,在 ([1,last_1]) 间的都合法。

    对于 (mathrm{xor}) 和,我们发现,所有的这一位数为 (1) 的数字,把数列分成了好几段。我们记 (cnt_0) 表示当 (a_{now}) 的这一位是 (0) 时有多少个左端点是能对答案产生贡献的。 (cnt_1) 同理。

    如果当前这位是 (0),那么答案累计上 (2 imes 2^k imes cnt_0 / n^2)(cnt_0 leftarrow cnt_0 + 1)

    如果当前这位是 (1),那么答案累计上 (2 imes 2^k imes cnt_1 / n^2)。然后交换 (cnt_0,cnt_1)(cnt_1 leftarrow cnt_1 + 1)

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int n, a[100005], lst0, lst1, cnt0, cnt1;
    double ansand, ansxor, ansor;
    int main(){
    	cin>>n;
    	for(int i=1; i<=n; i++)
    		scanf("%d", &a[i]);
    	for(int i=0; i<=29; i++){
    		lst0 = lst1 = cnt0 = cnt1 = 0;
    		for(int j=1; j<=n; j++){
    			int x=(a[j]>>i)&1;
    			if(x){
    				ansand += 1.0 * (1<<i) / n / n;
    				ansxor += 1.0 * (1<<i) / n / n;
    				ansor += 1.0 * (1<<i) / n / n;
    				ansand += 2.0 * (j - lst0 - 1) * (1<<i) / n / n;
    				ansor += 2.0 * (j - 1) * (1<<i) / n / n;
    				ansxor += 2.0 * cnt1 * (1<<i) / n / n;
    				swap(cnt0, cnt1);
    				cnt0++;
    				lst1 = j;
    			}
    			else{
    				ansxor += 2.0 * cnt0 * (1<<i) / n / n;
    				ansor += 2.0 * lst1 * (1<<i) / n / n;
    				cnt1++;
    				lst0 = j;
    			}
    		}
    	}
    	printf("%.3f %.3f %.3f
    ", ansxor, ansand, ansor);
    	return 0;
    }
    
  • 相关阅读:
    GKCTF2020
    PTA的Python练习题(二十三)
    Web刷题之旅(三)
    Web刷题之旅(二)
    Web刷题之旅(一)-攻防世界 站
    PTA的Python练习题(补)
    Ctfshow
    Ctfshow
    15、实操篇——Vi和Vim编译器
    13、14、实操篇——远程登录到Linux服务器和远程上传下载文件
  • 原文地址:https://www.cnblogs.com/poorpool/p/8545351.html
Copyright © 2020-2023  润新知