Solution

题目大意:给定两个序列a,b;那么答案序列c,就是当前位置前一项c的值,加上比当前位置小的j,对应数组分别异或a[i]和b[i],累加的和。可以画图举个栗子体会一下。如果觉得我再胡说八道可以自己理解理解题面

如果直接模拟。。O(N^2)炸的理所当然,那么就要想想别的路子。

通过题面给的条件,可以发现这个答案是一个递推的过程,说明已经求解的答案,之后不会更新。那么我们再根据,二进制异或的规律,不同数字异或才为0,我们发现如果当前位数j,之前出现过两次1,另外一组出现过3次0,那么后面计算这一位给答案贡献就会是(2 * 3)<< j。固定一个选后面的,在更换固定的。再结合这一组出现这个位置出现0,另外一组出现1,相乘之后,也是 <<j,累加就是当前位置的答案。
具体可以康康代码

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;

inline int read() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}

const int N = 1e6 + 7;
const int MOD = 1e9 + 7;
int a[N], b[N];
ll da[33][2], db[33][2], c[N];

int main() {
    int n = read();
    for (int i = 1; i <= n; ++i)    a[i] = read();
    for (int i = 1; i <= n; ++i)    b[i] = read();
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j <= 30; ++j) {
            ++da[j][(a[i] >> j) & 1]; //当前位出现0 or 1 次数+1
            ++db[j][(b[i] >> j) & 1]; //另外一组  0 or 1 次数+1
            c[i] += (da[j][1] * db[j][0] + da[j][0] * db[j][1]) << j;
            c[i] %= MOD;
        }
    }
    for (int i = 1; i <= n; ++i)
        printf("%lld ", c[i]);
    return 0;
}