codeforces1323D/codeforces1322B Present
老年退役选手打打CF玩玩,发现自己智力降低过多,差点DIV2连D都没做出来
题意: 有n个整数,\(a_{1} a_{2} …… a_{n}\),求 \((a_1 +a_2) \oplus(a_1+a_3)\oplus……(a_1+a_n)\oplus(a_2 + a_3)\oplus……(a_2+a_n)\oplus……(a_n-1 + a_n)\)
其中 \((2 \leq n \leq 400,000) (1 \leq a_i \leq 10^7)\)
考虑异或的性质,令\(b_{i,j} = (a_i + a_j)\),对于每一个二进制位需要得到所有的\(b_{i,j}\) 的那一位上的异或和。
考虑\(a_i , a_j\)对\(b_{i, j}\)的影响。
对于\(a_i , a_j\)的同一个二进制位,
不考虑进位当一个为0,一个为1时,\(b_{i, j}\)的对应位上得到一个1,
考虑进位,我们发现一个位是否有进位,跟右边的很多位都有关系,显然是无法记录状态进行DP的。
此时发现一个性质,对于两个二进制数的和,第i位是否进位,只与1~i-1位的和有关.
那么求进位就变得很简单了,我们只需要每次对所有\(a_i\)取前i位,然后计算i+1位发生了多少次进位就行(因为异或的性质,哪一对发生进位我们是不用关心的)
计算方式:取前i位,然后对新生成的数进行排序,维护一个从末尾单调向开头走的尾指针,求出发生进位的总次数
最后就把进位的贡献加在不考虑进位的贡献的结果上就行了
#include <bits/stdc++.h>
#include <tr1/unordered_map>
using namespace std;
inline void R (int &v) {
static char ch;
v = 0;
bool p = 0;
do {
ch = getchar();
if (ch == '-') p = 1;
} while (!isdigit(ch));
while (isdigit(ch)) {
v = (v + (v << 2) << 1) + (ch ^ '0');
ch = getchar();
}
if (p) v = -v;
}
inline void R (long long &v) {
static char ch;
v = 0;
bool p = 0;
do {
ch = getchar();
if (ch == '-') p = 1;
} while (!isdigit(ch));
while (isdigit(ch)) {
v = (v + (v << 2) << 1) + (ch ^ '0');
ch = getchar();
}
if (p) v = -v;
}
int n;
int a[400005];
int t[32];
int c;
inline bool cmp(const int a, const int b) {
return (a & t[c]) < (b & t[c]);
}
int one[32], zero[32];
long long newone[32];
inline void count(int x) {
int now = 1;
for(int i = 0; i <= 25; ++i) {
if(now & x) {
one[i]++;
} else {
zero[i]++;
}
now <<= 1;
}
}
int jinwei[32];
int main() {
R(n);
for(int i = 1; i <= n; ++i) {
R(a[i]);
}
for(int i = 1; i <= n; ++i) {
count(a[i]);
}
t[0] = 1;
for(int i = 1; i <= 31; ++i) t[i] = (t[i - 1] << 1) + 1;
for(int i = 0; i <= 26; ++i) {
c = i;
sort(a + 1, a + n + 1, cmp);
int tail = n + 1;
int now = 0;
for(register int j = 1; j <= n; ++j) {
if(j >= tail) {
jinwei[i + 1] += n - j;
continue;
} else {
while(((a[j] & t[c]) + (a[tail - 1] &t[c])) & (1 << i + 1) && (tail - 1 > j)) {
--tail;
++now;
}
jinwei[i + 1] += now;
}
}
}
for(int i = 0; i <= 27; ++i) {
newone[i] += (long long)one[i] * zero[i] + jinwei[i];
}
int now = 1;
int daan = 0;
for(int i = 0; i <= 25; ++i) {
if(newone[i] % 2) {
daan += now;
}
now <<= 1;
}
cout << daan << '\n';
return 0;
}