Problem
给出 n n n 个数,等概率地选取两个数 l l l、 r r r(如果 l > r l>r l>r,则交换 l l l、 r r r),把第 l l l 个数到第 r r r 个数取出来,构成一个数列 P \mathrm P P,现在请你计算三个值 a , b , c a,b,c a,b,c。
a a a 是数列 P \mathrm P P 的 x o r \mathrm{xor} xor 和的数学期望值。 x o r \mathrm{xor} xor 和就是数列 P \mathrm P P 中各个数异或之后得到的数; x o r \mathrm{xor} xor 和的期望就是对于所有可能选取的 l l l、 r r r,所得到的数列的 x o r \mathrm{xor} xor 和的平均数。
b b b 是数列 P \mathrm P P 的 a n d \mathrm{and} and 和的期望,定义类似于 x o r \mathrm{xor} xor 和。
c c c 是数列 P \mathrm P P 的 o r \mathrm {or} or 和的期望,定义类似于 x o r \mathrm{xor} xor 和。
数据范围: 1 ≤ n ≤ 100000 1\le n\le100000 1≤n≤100000, n n n 个自然数均不超过 1 0 9 10^9 109。
Solution
很好的一道题。
由于位运算是按位计算,各个位之间互不影响,所以我们可以把每个位拆开单独考虑。
按照题目中的选择方式,长度为 1 1 1 的序列(即 l = r l=r l=r)被选出来的概率为 1 n 2 \frac 1 {n^2} n21,其他的都是 2 n 2 \frac 2 {n^2} n22。因此,对于序列的每一个数,如果第 k k k 位是 1 1 1,就先累加 2 k × 1 n 2 2^k\times\frac 1 {n^2} 2k×n21 进答案。那么接下来就只用考虑长度 > 1 >1 >1 的序列了。
我们枚举右端点 r r r,用 l a s t k ( k = 0 , 1 ) last_k(k=0,1) lastk(k=0,1) 表示 k k k 上一次出现的位置。
对于 a n d \mathrm{and} and 和
显然只有当第 r r r 位是 1 1 1,且 l ∈ [    l a s t 0 + 1 , r − 1    ] l\in[\;last_0+1,r-1\;] l∈[last0+1,r−1] 时 a n d \mathrm{and} and 为 1 1 1。
所以第 r r r 位是 1 1 1 时,就累加 2 k × ( r − l a s t 0 − 1 ) × 2 n 2 2^k\times(r-last_0-1)\times \frac{2}{n^2} 2k×(r−last0−1)×n22。
对于 o r \mathrm{or} or 和
若第 r r r 位是 1 1 1,那 l ∈ [    1 , r − 1    ] l\in[\;1,r-1\;] l∈[1,r−1] 时 o r \mathrm{or} or 都是 1 1 1,此时累加 2 k × ( r − 1 ) × 2 n 2 2^k\times(r-1)\times \frac{2}{n^2} 2k×(r−1)×n22。
若第 r r r 位不是 1 1 1,那当 l ∈ [    1 , l a s t 1    ] l\in[\;1,last_1\;] l∈[1,last1] 时 o r \mathrm{or} or 是 1 1 1,此时累加 2 k × l a s t 1 × 2 n 2 2^k\times last_1\times \frac{2}{n^2} 2k×last1×n22。
对于 x o r \mathrm{xor} xor 和
如果我们枚举 l l l 从做左往右扫描,当遇到 0 0 0 时 x o r \mathrm{xor} xor 不变,遇到 1 1 1 时 x o r \mathrm{xor} xor 取反。
那我们可以以 1 1 1 作为分界,把序列分为几段,在同一段取 l l l 时 x o r \mathrm{xor} xor 的值相同,相邻段取 l l l 的 x o r \mathrm{xor} xor 相反。
我们建立两个变量 t 1 , t 2 t_1,t_2 t1,t2。 t 1 t_1 t1 记录从 r − 1 r-1 r−1 数起,第 1 , 3 , 5 , . . . 1,3,5,... 1,3,5,... 段的总长; t 2 t_2 t2 记录第 2 , 4 , 6 , . . . 2,4,6,... 2,4,6,... 段的总长。
当第 r r r 位是 1 1 1 时, t 1 t_1 t1 是能使 x o r \mathrm{xor} xor 为 1 1 1 的数的个数,那么此时累加 2 k × t 1 × 2 n 2 2^k\times t_1\times\frac{2}{n^2} 2k×t1×n22。
同理,当第 r r r 位是 0 0 0 时, t 2 t_2 t2 是能使 x o r \mathrm{xor} xor 为 1 1 1 的数的个数,此时累加 2 k × t 2 × 2 n 2 2^k\times t_2\times\frac{2}{n^2} 2k×t2×n22。
当右端点变为 r + 1 r+1 r+1 时,令 t 1 = t 1 + 1 t_1=t_1+1 t1=t1+1,若 r + 1 r+1 r+1 位是 1 1 1,还要交换 t 1 , t 2 t_1,t_2 t1,t2。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,a[N];
double Xor(){
int i,j;
double ans=0;
for(j=0;j<31;++j){
int t1=0,t2=0;
for(i=1;i<=n;++i){
if(a[i]&(1<<j)) ans+=1.0*(1<<j)*t1*2.0/n/n;
else ans+=1.0*(1<<j)*t2*2.0/n/n;
t1++; if(a[i]&(1<<j)) swap(t1,t2);
}
}
return ans;
}
double And(){
int i,j;
double ans=0;
for(j=0;j<31;++j){
int last0=0;
for(i=1;i<=n;++i){
if(a[i]&(1<<j))
ans+=1.0*(1<<j)*(i-last0-1)*2.0/n/n;
if(!(a[i]&(1<<j))) last0=i;
}
}
return ans;
}
double Or(){
int i,j;
double ans=0;
for(j=0;j<31;++j){
int last1=0;
for(i=1;i<=n;++i){
if(a[i]&(1<<j)) ans+=1.0*(1<<j)*(i-1)*2.0/n/n;
else ans+=1.0*(1<<j)*last1*2.0/n/n;
if(a[i]&(1<<j)) last1=i;
}
}
return ans;
}
int main(){
double temp=0;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),temp+=1.0*a[i]/n/n;
printf("%.3lf %.3lf %.3lf",temp+Xor(),temp+And(),temp+Or());
return 0;
}