UESTC 1709 Binary Operations (位运算)

17 篇文章 0 订阅

Submit

Status

Best Solution

Back

Description

Bob has a sequence of N integers. They are so attractive, that Alice begs to have a continued part of it(a continued part here also means a continued subsequence). However, Bob only allows Alice to chose it randomly. Can you give the expectation of the result of the bitwise AND, OR, XOR of all the chosen numbers?

Input


First line of the input is a single integer T(1 <= T <= 50), indicating there are T test cases.

The first line of each test case contains a single number N(1 <= N <= 50000).

The second line contains N integers, indicating the sequence.

All the N integers are fit in [0, 10^9].

Output

For each test case, print "Case #t: a b c" , in which t is the number of the test case starting from 1, a is the expectation of the bitwise AND, b is the expectation of OR and c is the expectation of XOR.

Round the answer to the sixth digit after the decimal point.

Sample Input

3
2
1 2
3
1 2 3
3
2 3 4

Sample Output

Case #1: 1.000000 2.000000 2.000000
Case #2: 1.333333 2.500000 1.666667
Case #3: 1.833333 4.333333 3.666667

Hint

AND is a binary operation, performed on two numbers in binary notation. First, the shorter number is prepended with leading zeroes until both numbers have the same number of digits (in binary). Then, the result is calculated as follows: for each bit where the numbers are both 1 the result has 1 in its binary representation. It has 0 in all other positions.

OR is a binary operation, performed on two numbers in binary notation. First, the shorter number is prepended with leading zeroes until both numbers have the same number of digits (in binary). Then, the result is calculated as follows: for each bit where the numbers are both 0 the result has 0 in its binary representation. It has 1 in all other positions.

XOR is a binary operation, performed on two numbers in binary notation. First, the shorter number is prepended with leading zeroes until both numbers have the same number of digits (in binary). Then, the result is calculated as follows: for each bit where the numbers differ the result has 1 in its binary representation. It has 0 in all other positions.

Source

Sichuan State Programming Contest 2012

思路:(转自:http://www.cnblogs.com/dgsrz/articles/2575682.html

如果本题数据范围不大,可以直接暴力,即枚举每个序列,分别进行AND\OR\XOR操作,然后求和求期望。但这样明显时间复杂度不够。为此需要进行一些优化。
注意到,对于“A1 A2 A3...”这样的案例,以A1为末尾的子序列有A1,A2为末尾的有A1 A2、A2,A3为末尾的有A3、A2 A3、A1 A2 A3……而以与运算为例,所有子序列位运算之后求和,有:A1 + [(A2&A1) + A2] + [(A3&A2&A1 + A3&A2) + A3] + ……。显然,后一个子序列进行的操作和前一个有关。为此,考虑到数据范围0-10^9,开一个至少30位的数组num[30],存储进行到当前步骤时(即以第i个数字结尾的子序列),每一位上剩余几个1。
初始化这个数组全部为0。然后仍以与运算为例,进行如下操作:
先将这个第i个末尾化为二进制,然后每一位与上一次的状态进行比较。考虑与运算性质,如果这个末尾的二进制表示某一位 j 是0,则结果一定是0,即剩余0个1,故num[j] = 0。若第j位为1,则原来有几个1,与运算之后也有几个1,根据num[j]表示意义,其值不变。
对于或运算,当第j位为1,则num[j]就与执行次数有关(有m个数进行操作,则与运算之后这一位全是1)。假定当前进行到第i个数字,num[j] = i。若第j位为0,num[j]不变。
对于异或,当第j位为1,则num[j]和当前结果这一位有几个0有关。当前结果有几个0,有与num[j](有几个1)和执行次数(总共操作m个数)有关,故num[j]=i-num[j]。若第j位为0,则num[j]不变。
每进行完一次位运算,需要将整个序列的第i个末尾加到状态中(参考上述公式),然后求得当前第i个数为结尾的子序列进行操作后,新值的和。根据num[j]的意义,无非就是将num[j]存储的二进制转为十进制。
最后,求出所有数为结尾的子序列的和S,又因为每种情况都是等可能,求出事件总数 Q=n*(n+1)/2,得E=S/Q。得解。
进行如上优化后,每一位数字只进行30次计算,相比最初的暴力可以节省相当多的时间。

总结:

这道题依旧考察位运算的掌握。代码不是重点,但上述思想,如果缺乏对位运算的深刻理解,恐怕很难想到。
当初比赛的时候,我也没想到可以这样转化,纯粹的暴力导致了超时。后来也是询问了做出来的同学,一讲解思路就清晰了不少。


#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
const long M=51000;
const long MPOS=31;
long t,n,num[3][MPOS+5];
LL ans[3];
int main(){
	scanf("%d",&t);
	for (long i=1;i<=t;++i){
		scanf("%d",&n);
		double sum=1.0*(LL)n*(n+1)/2.0;
		memset(num,0,sizeof(num));
		memset(ans,0,sizeof(ans));
		for (long j=1;j<=n;++j){
			long x;
			scanf("%d",&x);
			for (long k=0;k<MPOS;++k){
				if (x & (1<<k)){
					num[0][k]++;
					num[1][k]=j;
					num[2][k]=j-num[2][k];
				}
				else
					num[0][k]=0;
				for (long l=0;l<3;++l)
					ans[l]+=num[l][k]*((LL)1<<k);
			}
		}
		printf("Case #%d: %.6lf %.6lf %.6lf\n",i,ans[0]/sum,ans[1]/sum,ans[2]/sum);
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值