zoukankan      html  css  js  c++  java
  • 【bzoj4888】: [Tjoi2017]异或和 BIT-乱搞

    【bzoj4888】: [Tjoi2017]异或和

    题目大意:给定一个序列,求这个序列所有的连续和的异或值。(n<=1e5 ai<=1e6)

    想了各种奇怪的方法就是不会做啊啊啊。。

    Orz 参考了一下 http://www.cnblogs.com/xiejiadong/p/6815269.html 才会做的。。

    恩因为不超过20位。。所以可以考虑枚举所有连续和在第i位1的个数

    预处理完前缀和就可以O(1)求出任意一个连续和。。

    当考虑到第i位的时候,把前缀和扫一遍

    当扫到第x个前缀和sum[x],那么所有满足 第y个前缀和sum[y](y<x)的第i位=sum[x] 的第i位 且 sum[x]的i后面的位<sum[y]的i后面的位

                      或 第y个前缀和sum[y](y<x)的第i位!=sum[x] 的第i位 且 sum[x]的i后面的位>sum[y]的i后面的位

    的sum[x]-sum[y]一定是一个对第i位有贡献的连续和。。

    理解了半天。。手玩了几个数才明白。。在扫一遍的时候用BIT维护一下就好了。。

     1 /* http://www.cnblogs.com/karl07/ */
     2 #include <cstdlib>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <cmath>
     6 #include <algorithm>
     7 using namespace std;
     8 
     9 #define lowbit(x) (x&-x)
    10 const int N=1e5+5;
    11 const int MX=1e6+1e5;
    12 int n,m;
    13 int a[N],b[2][MX],as[21];
    14 
    15 int bt(int x,int y){
    16     return (x>>(y-1))&1;
    17 }
    18 
    19 void PR(int x){
    20     if (x) PR(x>>1);
    21     printf("%d",x&1);
    22 }
    23 void pr(int x){
    24     PR (x);
    25     puts("");
    26 }
    27 
    28 int query(int p1,int x){
    29     int ans=0;
    30     while (x){
    31         ans+=b[p1][x];
    32         x-=lowbit(x);
    33     }
    34     return ans;
    35 }
    36 
    37 void modify(int p1,int x){    
    38     while (x<=MX){
    39         b[p1][x]++;
    40         x+=lowbit(x);
    41     }
    42 }
    43 
    44 int main(){
    45     scanf("%d",&n);
    46     for (int i=1;i<=n;i++){
    47         scanf("%d",&a[i]);
    48         a[i]+=a[i-1];
    49     }
    50     for (int i=1,ba=1;i<=20;i++){
    51         memset(b,0,sizeof(b));
    52         for (int j=1;j<=n;j++){
    53             as[i]+=query(bt(a[j],i),ba+1)-query(bt(a[j],i),a[j]%ba+1)+query(!bt(a[j],i),a[j]%ba+1)+bt(a[j],i);
    54             modify(bt(a[j],i),a[j]%ba+1);
    55         }
    56         ba=ba*2;
    57     }
    58     int ans=0;
    59     for (int i=1,ba=1;i<=20;i++,ba*=2) ans+=(as[i]&1)*ba;
    60     printf("%d
    ",ans); 
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    Linux系统中/和是什么意思,和window系统有什么区别?
    给自己的U盘设定图标
    我的第一篇文章
    大端小端
    好玩的地图
    英语流利说 第28天
    英语流利说 第27天
    英语流利说 第26天
    英语流利说 第25天
    英语流利说 第24天
  • 原文地址:https://www.cnblogs.com/karl07/p/6914171.html
Copyright © 2011-2022 走看看