[ARC092D] Two Sequences
Time Limit: 3 sec / Memory Limit: 256 MB
难度:4.0
You are given two integer sequences, each of length N: a_1, \cdots ,a_N and b_1, \cdots ,b_N.
There are N^2 ways to choose two integers i and j such that 1 \leq i,j \leq N. For each of these N^2 pairs, we will compute a_i+b_j and write it on a sheet of paper. That is, we will write N^2 integers in total.
Compute the XOR of these N^2 integers.
给定两个长度为 n 的正整数数组 a,b ,求 \forall 1 \leq i,j \leq n,a_i+b_j 在二进制下的异或和 。
n 和两数组 a,b 。
答案。
1 \leq n \leq 200000,1 \leq a_i,b_j \leq 2^{28}。
Source:ARC092D
from orz zzx:
对每一位 d,求有多少对 i,j 满足 a_i+b_j 的第 d 位为 1,也就是 (a_i+b_j) \bmod 2d+1 \geq 2d,单调性扫一扫就行了,复杂度 O(n(\log a_i+\log b_i))。
这题比我在泉州集训出的某个题略微简单一点,那个题是求所有 l \leq r
的 \sum\limits_{i=l}^r a_i 的异或和,思路类似。
from sb mnihyc:
「单调性扫一扫」想得不是很清楚的可以直接排序+二分。
具体来说就是:枚举位,要查找序列中有多少个数当前位为 1。
如果要查找 N 次的话,普通查找的复杂度就是 N^2。
显然我们可以通过排序优化这个操作。
将其中一个数组排序后再查找,目标就变成了有序序列中连续的单调的一段,使用二分,复杂度 O(n \log n)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #include <algorithm> #define _max(_a_,_b_) ((_a_)>(_b_)?(_a_):(_b_)) #ifdef ONLINE_JUDGE char __B[1<<15],*__S=__B,*__T=__B; #define getchar() (__S==__T&&(__T=(__S=__B)+fread(__B,1,1<<15,stdin),__S==__T)?EOF:*__S++) #endif inline int getnum() { register char c=0; while(!(c>='0' && c<='9')) c=getchar(); register int a=0; while(c>='0' && c<='9') a=a*10+c-'0',c=getchar(); return a; } int a[205050],b[205050]; #define GetLen(_arr,_l,_r) (std::lower_bound(&(_arr)[1],&(_arr)[N+1],_r)-std::lower_bound(&(_arr)[1],&(_arr)[N+1],_l)) int ta[205050],tb[205050]; int main() { register int N=getnum(),mxv=0; for(register int i=1;i<=N;i++) a[i]=getnum(),mxv=_max(mxv,a[i]); for(register int i=1;i<=N;i++) b[i]=getnum(),mxv=_max(mxv,b[i]); register unsigned dig=1; while(mxv) dig++,mxv>>=1; int ans=0,pw2=1; while(dig--) { for(register int i=1;i<=N;i++) ta[i]=a[i]&((pw2<<1)-1),tb[i]=b[i]&((pw2<<1)-1); std::sort(&tb[1],&tb[N+1]); register bool sum=0; for(register int i=1;i<=N;i++) sum^=GetLen(tb,pw2-ta[i],(pw2<<1)-ta[i])&1, sum^=GetLen(tb,pw2+(pw2<<1)-ta[i],(pw2<<2)-ta[i])&1; ans|=pw2*sum,pw2<<=1; } printf("%d\n",ans); return 0; } |