题目链接:戳这里
记 n 个数为 a[0], a[1], ... , a[n-1], 由于取的是连续片段,故我们可以以末尾元素为分类依据进行讨论。
显然,以 a[i] (i=0,...,n-1) 为末尾的子序列有 i+1 个,分别为:
a[i], a[i-1]a[i], ... , a[0]a[1]...a[i].
故总的个数为 all=1+2+...+n=n*(n+1)/2.
考虑到 a[i] (i=0,...,n-1) 的取值范围为 [0, 10^9] < 2^30, 我们令:
one[j]=2^(j-1), (j=1,2,...,30).
分别以 b[j], c[j], d[j] 表示与、或、异或运算第 j 位的 1 的个数,初始为 0. 以sum1, sum2, sum3 表示与、或、异或运算的和,初始为 0.
对于与运算(1&1=1),如果 a[i]&one[j] 为真,则 b[j] 的值加 1, 否则 b[j]=0. sum1+=b[j]*one[j].
对于或运算(1|x=1),如果 a[i]&one[j] 为真,则 c[j]=i+1, 否则 c[j] 保持不变,sum2+=c[j]*one[j].
对于异或运算(1^0=0^1=1),如果 a[i]&one[j] 为真,则 d[j]=i+1-d[j] , 否则 d[j] 保持不变,sum3+=d[j]*one[j].
最终的期望值为:sum1/all, sum2/all, sum3/all.
AC Code
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 int main(){ 6 int T,t,i,j; 7 long long n,temp=1,a[50005],b[35],c[35],d[35],one[35]; 8 for(i=1;i<=30;i++){ 9 one[i]=temp; 10 temp<<=1; 11 } 12 cin>>T; 13 for(t=1;t<=T;t++){ 14 cin>>n; 15 for(i=0;i<n;i++) cin>>a[i]; 16 double all=n*(n+1)/2; 17 long long sum1=0,sum2=0,sum3=0; 18 for(i=1;i<=30;i++) b[i]=c[i]=d[i]=0; 19 for(i=0;i<n;i++){ 20 for(j=1;j<=30;j++){ 21 if(a[i]&one[j]){ 22 b[j]++; 23 c[j]=i+1; 24 d[j]=i+1-d[j]; 25 } 26 else b[j]=0; 27 sum1+=b[j]*one[j]; 28 sum2+=c[j]*one[j]; 29 sum3+=d[j]*one[j]; 30 } 31 } 32 printf("Case #%d: %.6lf %.6lf %.6lf ",t,sum1/all,sum2/all,sum3/all); 33 } 34 return 0; 35 }
By 林秋伟