D - Two Sequences
Time limit : 3sec / Memory limit : 256MB
Score : 500 points
Problem Statement
You are given two integer sequences, each of length N: a1,…,aN and b1,…,bN.
There are N2 ways to choose two integers i and j such that 1≤i,j≤N. For each of these N2 pairs, we will compute ai+bj and write it on a sheet of paper. That is, we will write N2 integers in total.
Compute the XOR of these N2 integers.
Definition of XORConstraints
- All input values are integers.
- 1≤N≤200,000
- 0≤a i , b i<228
Input
Input is given from Standard Input in the following format:
N a 1 a 2 … a N b 1 b 2 … b N
Output
Print the result of the computation.
Sample Input 1
2 1 2 3 4
Sample Output 1
2
On the sheet, the following four integers will be written: 4(1+3),5(1+4),5(2+3) and 6(2+4).
Sample Input 2
6 4 6 0 0 3 3 0 5 6 5 0 3
Sample Output 2
8
Sample Input 3
5 1 2 3 4 5 1 2 3 4 5
Sample Output 3
2
Sample Input 4
1 0 0
Sample Output 4
0
这道题的意义在于把数拆成二进制,顶多28位,那么二进制的每一位要么是0,要么是1,先拆第一组,在将第二组每一个数按位拆开,看会不会与第一组值的相同位产生进位,有进位的的直接异或和就OK,没有的不用管,你会发现如果这样写不优化复杂度会达到O(28*n*n),会超时,优化,把第一组数按位排序,然后二分去找即可。比如第二组中的一个数一位是0,那么就不可能产生进位,因为第一组这位上找不到2(只有0或1;第二组中的一个数一位是1,那那么二分搜索出1的位置k即可,利用(n-k+1)就是这个数在这一级上产生进位的数量。复杂度可降至O(28*nlogn).然后算不进位的.第一组同位上0的个数a,1的个数b;第二组同位上0的个数c,1的个数d;公式为((a*d)%2+(b*c)%2)%2,直接和之前的进位异或值异或即可。所以复杂度为O(30*n)
主要是二进制+异或和时时处理+二分 O(28*nlogn+30*n)
//aaakirito #include <cstdio> #include <algorithm> using namespace std; #define mmax 200000+10 int a[mmax],b[mmax],x[30][mmax],y[mmax]; int fun(int k,int n,int v){//二分 int l=1,r=n; int h=(l+r)/2; while(l<=r){ if(v<=x[k][h]&&x[k][h-1]<v) return h; else if(v<=x[k][h]) r=h-1; else if(v>x[k][h]) l=h+1; h=(l+r)/2; } return n+1; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int k=0;k<28;k++){ if(k==0) for(int i=1;i<=n;i++) x[k][i]=a[i]&1;//2ˆ0次幂,a[i]最后一位的拆分 else for(int i=1;i<=n;i++) x[k][i]=x[k-1][i]^((1<<k)&a[i]);// 取出其a[i]后k位 } long long ans=0; for(int k=0;k<28;k++) sort(x[k]+1, x[k]+1+n); for(int k=1;k<=28;k++){ for(int i=1;i<=n;i++){ y[i]^=(1<<(k-1))&b[i];//取出a[i]后k位 int t=fun(k-1,n,(1<<k)-y[i]);//二分查找会产生进位项的位子,下的low_bound也对 //int t=int(lower_bound(x[k-1]+1, x[k-1]+1+n, (1<<k)-y[i])-x[k-1]); ans^=(((n-t+1)%2)<<k);//产生进位的异或和 } } int q,w,e,r; for(int k=0;k<28;k++){ q=w=e=r=0; for(int i=1;i<=n;i++){//算a[i]里的第k位的奇偶数量 0,1 if((1<<k)&a[i]) q++; else w++; } for(int i=1;i<=n;i++){//算b[i]里的第k位的奇偶数量 0,1 if((1<<k)&b[i]) e++; else r++; } ans^=(((((long long)1)*q*r%2+((long long)1)*w*e%2)%2)<<k);///产生不进位的异或和 } printf("%lld\n",ans); return 0; }