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; }