题解:
首先我们要分析一下这个公式
举个例子来看,假设A数组与B数组的元素个数都为2。
不难发现每次求的答案就是
当然我们不能暴力,这样时间复杂度是O(n^2)
因此我们需要考虑异或的定义:
我们把每一个数转换成一个30位的二进制数考虑,那么对于A数组和B数组两个数的某一位而言,如果这两个数的相同位上,一个为0,一个为1,那么这个位就会对答案产生贡献。
我们可以考虑记录一下所有位上的0的个数和1的个数,
那么对于某个数某一位而言,对答案的贡献就是 cnt*(1<<i),i表示当前是第i位
cnt = A数组当前位上0的个数乘以B数组当前位上1的个数 + A数组当前位上1的个数乘以B数组当前位上0的个数
还是举个例子来说明一下。我们需要维护两个数组个A[j][0/1]和B[j][0/1]表示A数组(B数组)中第j位为0/1的个数。
当枚举到到第一位答案很明确就是 ,考虑每一位对答案的贡献即可,比较容易理解。
当枚举到第二位是,我们枚举A2与B2的每一位,对于第0位而讲,首先把A2与B2第0位的0/1的数加上去。
然后考虑A数组第0位为1的个数(包括之前第一位累加的)与 B数组第0位为0的的个数(包括之前第一位累加的)的乘积
相当于考虑的A1和A2第0位的0的个数和B1和B2第0位的1的个数乘积,这很显然是正确的。
假设A1与A2的第0位都是0,B1与B2第0位都为1,那么对答案的贡献就是4*(1<<i),即(1+1)*(1+1)*(1<<i)
剩下的类比一下就行了。
代码实现(比较简短):
#include<bits/stdc++.h> #define rp(i,s,t) for(int i=s;i<=t;i++) #define ll long long using namespace std; const ll mod = 1e9+7; const int N = 1e5+7; ll a[N],b[N],A[32][2],B[32][2]; int main(){ int n;cin>>n; rp(i,1,n) cin>>a[i]; rp(i,1,n) cin>>b[i]; rp(i,1,n){ ll res=0; rp(j,0,30){ A[j][(a[i]>>j)&1]++;B[j][(b[i]>>j)&1]++; ll cnt=(A[j][0]*B[j][1]%mod+A[j][1]*B[j][0]%mod)%mod; res=(res+cnt*1ll*(1<<j)%mod)%mod; } cout<<res%mod<<((i==n)?"\n":" "); } return 0; }
Rinne Love Xor——异或性质
最新推荐文章于 2021-04-28 15:32:34 发布