【bzoj4888】: [Tjoi2017]异或和 BIT-乱搞
题目大意:给定一个序列,求这个序列所有的连续和的异或值。(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 }