今天生日捏,嘻嘻~
题意:给定A B数组长度为n 求所有 (1<=i,j <=n ) a[i]+b[j] 的异或和。 n <=200000 ai bi <=228
这题比赛没写出来,而且完全没思路,结束后看了zz大佬的博客大致有了解题方向,然后再参考了cyc的...于是大致会写了。
由于xor 实际上是每一位的xor ,所以考虑一位一位的算出答案。(即算出答案在二进制下的每一位的数字 0 或 1)
ps:以下的每一个数都为二进制,位数从右往左数。
可以证明,已知 某一位上有 x 个 1 y 个0 的话, 这一位上xor后为 x mod 2。
这样就将问题转换为: 求所有 a[i]+b[j] 在二进制下,每一位分别的 1 的个数 之和。
举个栗子!
如样例
001 010
011 100
a[i]+b[j]分别为:
100
101
101
110
第1位有0 1 1 0 共2个 1 mod 2后为 0 (从左往右的第3位)
第2位有0 0 0 1 共1个 1 mod 2后为 1 (从左往右的第2位)
第3位有1 1 1 1 共4个 1 mod 2后为 0 (从左往右的第1位)
于是答案就是 (010)2=(2)10
然后就可以开始一位位的考虑了
当我们计算答案的第 k 位时,发现 a[i] b[j] 的k+1位之后的 (如当k=2 ,a[i]=100,那么k+1为之后的即 1)
对第k位的答案是没有作用的,因为当a[i]+b[j]后,k+1位之后的数对k没有任何影响。
所以就可以将k+1之后的都给扔掉。
于是我萌设
c[i]=a[i] and ((1 << k)-1)
d[i]=b[i] and ((1 << k)-1)
and ((1 << k)-1) 就相当于可以把k位都拿出来了
如 一个数10101110 k=4 那么
10101110 and
00001111
=00001110
至于为什么可以就自己思考一下。
由于0的个数是没有用的,所以考虑1就好了
发现0<=c[i],d[j]< 2k
对于第k位可以有一个 1
只有满足
①2k-1<=c[i]+d[j]<2k 这个就相当于
c[i]+d[j]没有向下一位进 1 而且第 k 位会是 1 因为 2k-1 相当于在第k位有一个1 其他都为0 而2k 相当于第k+1位有一个1其他都为0
这样的一个范围里就包含了所有第k位是1的所以数 ,而c[i]+d[j] 在这个范围里 所以说明对第 k 位有一个1 的贡献。
或
②2k+2k-1<=c[i]+d[j]<2k+1
类比第一个,这个就是对下一位进1 后的且第k为是1。
一样可以得到这样的一个范围能满足 第k+1位是1 且 第k位是1。
那到底有多少个c[i]+d[j] 是在以上的两个范围的其中一个
只要求出有多少个这样的数对 (i,j) 满足 c[i]+d[j] 是以上两个范围里的其中一个,问题就解决了(求出了有多少个1了)
考虑固定 j 移动 i
把c数组从小到大排序。
只要找到最左的 i (L)和最右的 i(R) 这样由于单调性 L~R 中的 i 都是满足条件的,所以 R-L+1即是1的个数。
所以分两类 分别计算出两类的个数加起来即可
而对于L R 用二分就好了。
这题是我接触的比较新的题,写详细些,自己因为二分一个小地方敲错了一直tle,以后要注意。
最后的话,生日快乐!
1 var n:longint; 2 i,k:longint; 3 a,b,c,d,heap:array[0..201000]of int64; 4 m0,m1:int64; 5 ans,tot,x,y:int64; 6 procedure swap(var a,b:int64); 7 var t:longint; 8 begin 9 t:=a;a:=b;b:=t; 10 end; 11 procedure up(x:longint); 12 begin 13 while x>1 do 14 begin 15 if heap[x]<heap[x div 2] then 16 begin 17 swap(heap[x],heap[x div 2]); 18 x:=x div 2; 19 end else break; 20 end; 21 end; 22 procedure down(x:longint); 23 var min:longint; 24 begin 25 while x*2<=tot do 26 begin 27 min:=x*2; 28 if (x*2+1<=tot)and(heap[x*2+1]<heap[min]) then inc(min); 29 if heap[x]>heap[min] then 30 begin 31 swap(heap[x],heap[min]); 32 x:=min; 33 end else break; 34 end; 35 end; 36 37 procedure sort; 38 var i,j:longint; 39 begin 40 for i:=1 to n do 41 begin 42 c[i]:=heap[1]; 43 heap[1]:=heap[tot]; 44 dec(tot); 45 down(1); 46 end; 47 end; 48 function find(x:int64):longint; 49 var l,r,m:longint; 50 begin 51 l:=1; 52 r:=n; 53 while l<=r do 54 begin 55 m:=(l+r)>>1; 56 if c[m]<x then l:=m+1 else r:=m-1; 57 end; 58 exit(l); 59 end; 60 61 begin 62 read(n); 63 for i:=1 to n do 64 read(a[i]); 65 for i:=1 to n do 66 read(b[i]); 67 c[0]:=-1; 68 c[n+1]:=1 << 45; 69 for k:=1 to 29 do 70 begin 71 tot:=0; 72 x:=1 << k; 73 y:=1 << (k-1); 74 for i:=1 to n do 75 begin 76 heap[i]:=a[i] and (x-1); 77 inc(tot); 78 up(i); 79 d[i]:=b[i] and (x-1); 80 end; 81 //writeln(k); 82 sort; 83 m0:=0; 84 m1:=0; 85 for i:=1 to n do 86 begin 87 m1:=m1+find(x-d[i])-find(y-d[i]); 88 m1:=m1+n+1-find(x+y-d[i]); 89 //inc(m1); 90 end; 91 //writeln(‘0=‘,m0,‘ 1=‘,m1); 92 if m1 and 1 =1 then ans:=ans+y; 93 end; 94 writeln(ans); 95 end.