UVALive8518 Sum of xor sum

Posted blogggggg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVALive8518 Sum of xor sum相关的知识,希望对你有一定的参考价值。

题目链接:https://vjudge.net/problem/UVALive-8518

题目大意:

  给定一个长度为 $N$ 的数字序列 $A$,进行 $Q$ 次询问,每次询问 $[L,R]$,需要回答这个区间内的子序列的所有子序列的异或和之和。

  $1 le N,Q le 100000$

  $0 le A[i] le 1000000$

知识点:  前缀和

解题思路:

  将序列中的每一个数转成二进制(不超过 $20$ 位),逐位考虑。

  根据序列中的数字用二进制表示时在该位上为 $1$ 或 $0$,我们可以用 $20$ 个 $01$ 序列来表示序列 $A$。现在只考虑二进制位中的某一位,其他位做类似处理即可:

  先预处理出异或前缀和 $preXOR$(很明显,它是个 $01$ 序列),用 $zero[][i]$ 和 $one[][i]$ 表示在 $[1,i]$ 这个区间中的 $preXOR$ 有多少个 $0$  和 $1$。然后用 $sum[][i]$ 表示 $[1,i]$ 这个区间的答案。易知 $sum[][i] = sum[][i-1] + (所有以 A[i] 为右边界的子序列对答案的贡献)$,即 $sum[j][i] = sum[j][i-1] + 2^j *(preXOR[j][i]:zero[j][i-1]?one[j][i-1])$,因为只有当左边界的左边一位的异或前缀和和右边界的异或前缀和的异或和为 $1$ 时该区间才对答案有贡献。

  查询 $[L,R]$ 的时候,对于第 $j$ 位,对答案的贡献为:$sum[j][R]-sum[j][L-1]-zero[j][L-2]*(one[j][R]-one[j][L-1])*2^j -one[j][L-2]*(zero[j][R]-zero[j][L-1])*2^j$.

  后半部分其实是减掉那些左边界在 $[1,L-1]$ 而右边界在 $[L,R]$ 的区间对答案的影响,还是一样的道理: 只有当左边界的左边一位的异或前缀和和右边界的异或前缀和的异或和为 $1$ 时该区间才对答案有贡献。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 const int MAXN=100000+5;
 6 const int MOD=1e9+7;
 7 
 8 int A[MAXN];
 9 int preXOR[24][MAXN];
10 LL sum[24][MAXN],zero[24][MAXN],one[24][MAXN];
11 int main(){
12     int T;
13     scanf("%d",&T);
14     while(T--){
15         int N,Q;
16         scanf("%d%d",&N,&Q);
17         for(int i=1;i<=N;i++)   scanf("%d",&A[i]);
18         for(int i=0;i<20;i++){
19             preXOR[i][0]=0;
20             one[i][0]=0,zero[i][0]=1;
21             for(int j=1;j<=N;j++){
22                 if(A[j]&(1<<i))
23                     preXOR[i][j]=preXOR[i][j-1]^1;
24                 else
25                     preXOR[i][j]=preXOR[i][j-1];
26                 one[i][j]=one[i][j-1],zero[i][j]=zero[i][j-1];
27                 if(preXOR[i][j])    one[i][j]++;
28                 else                zero[i][j]++;
29             }
30         }
31         for(int i=0,now=1;i<20;i++,now<<=1){
32             sum[i][0]=0;
33             for(int j=1;j<=N;j++){
34                 sum[i][j]=sum[i][j-1];
35                 if(preXOR[i][j])
36                     sum[i][j]=(sum[i][j]+zero[i][j-1]*now)%MOD;
37                 else
38                     sum[i][j]=(sum[i][j]+one[i][j-1]*now)%MOD;
39             }
40         }
41         while(Q--){
42             int L,R;
43             scanf("%d%d",&L,&R);
44             LL ans=0;
45             for(int i=0,now=1;i<20;i++,now<<=1){
46                 ans=(ans+sum[i][R]-sum[i][L-1])%MOD;
47                 if(L>=2)
48                     ans=(ans-zero[i][L-2]*(one[i][R]-one[i][L-1])*now%MOD
49                          -one[i][L-2]*(zero[i][R]-zero[i][L-1])*now%MOD)%MOD;
50             }
51             if(ans<0)   ans+=MOD;
52             printf("%lld
",ans);
53         }
54     }
55     return 0;
56 }

 

 

以上是关于UVALive8518 Sum of xor sum的主要内容,如果未能解决你的问题,请参考以下文章

SOJ 4309 Sum of xor 异或/思维

UVALive-3716 DNA Regions

UVa 12716 && UVaLive 6657 GCD XOR (数论)

371. Sum of Two Integers

LeetCode 371 Sum of Two Integers

UVALive 6661 - Equal Sum Sets