zoukankan      html  css  js  c++  java
  • 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$ 时该区间才对答案有贡献。

      "为什么是l-2,因为左端点要<=l-1,如果是l-1的话就表示从l开始了。"

    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 }

     

    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    社区专家谈 12306
    一致性Hash算法(分布式算法)
    ASP.NET二级域名站点共享Session状态
    树莓派2 安装 win10Iot 和 Ubuntu mate
    Maven运行时异常java.lang.UnsupportedClassVersionError的解决方案
    Ubuntu安装steam游戏平台的解决方案
    Spring配置JNDI的解决方案
    Intellij Idea无法从Controller跳转到视图页面的解决方案
    电话激活windows server 2012的解决方案
    如何下载Red Hat Enterprise Linux系统
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/9749707.html
Copyright © 2011-2022 走看看