codeforces1323D Present

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;
	
}
posted @ 2020-03-08 11:34  thhyj  阅读(189)  评论(0)    收藏  举报