【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\n",ans); 
61     return 0;
62 }
View Code

 

posted @ 2017-05-27 19:05  karl07  阅读(315)  评论(0编辑  收藏  举报