Codeforces 1322B - Present

Description

给出序列 a i a_i ai, 求两两之和的异或值

Solution

按位计算
计算到第 k k k 位时,将 a i a_i ai m o d   2 k + 1 mod \ 2^{k+1} mod 2k+1 后排序
a i   m o d   2 k + 1 + a j   m o d   2 k + 1 ∈ [ 2 k ,   2 k + 1 − 1 ] ∪ [ 2 k + 1 + 2 k , 2 k + 2 − 2 ] a_i \ mod \ 2^{k+1} + a_j \ mod \ 2^{k+1}\in [2^k, \ 2^{k+1} - 1] \cup [2^{k + 1} + 2^k, 2^{k+2}-2] ai mod 2k+1+aj mod 2k+1[2k, 2k+11][2k+1+2k,2k+22], 这两数和的第 k k k 位为 1 1 1
排序时每次加入一位重排可用归并排序,找区间可以用双指针
复杂度 O ( n l o g M a x ) O(n log Max) O(nlogMax)

#include <bits/stdc++.h>
using namespace std;


inline int read() {
	int out = 0;
	bool flag = false;
	register char cc = getchar();
	while (cc < '0' || cc > '9') {
		if (cc == '-') flag = true;
		cc = getchar();
	}
	while (cc >= '0' && cc <= '9') {
		out = (out << 3) + (out << 1) + (cc ^ 48);
		cc = getchar();
	}
	return flag ? -out : out;
} 

inline void write(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x == 0) putchar('0');
	else {
		int num = 0;
		char cc[15];
		while (x) cc[++num] = x % 10 + 48, x /= 10;
		while (num) putchar(cc[num--]);
	}
	putchar('\n');
}


int N, a[400010], b[400010], l1, r1, l2, r2, cnt, ans;

queue<int> q1, q2; 

int main() {
	N = read();
	for (int i = 1; i <= N; i++) a[i] = read(), b[i] = i;
	for (int k = 0; k <= 24; k++) {
		for (int i = 1; i <= N; i++) 
			if (a[b[i]] & (1 << k)) q1.push(b[i]);
			else q2.push(b[i]);
		int o = 0; 
		while (!q2.empty()) b[++o] = q2.front(), q2.pop();
		while (!q1.empty()) b[++o] = q1.front(), q1.pop();
		l1 = l2 = N + 1, r1 = r2 = N, cnt = 0;
		int Mod = (1 << (k + 1)) - 1;
		for (int i = 1; i <= N; i++) {
			o = (a[b[i]] & Mod);
			while (l1 >= 2 && o + (a[b[l1 - 1]] & Mod) >= (1 << k)) l1--;
			while (r1 >= 1 && o + (a[b[r1]] & Mod) >= (1 << (k + 1))) r1--;
			while (l2 >= 2 && o + (a[b[l2 - 1]] & Mod) >= (1 << (k + 1)) + (1 << k)) l2--;
			while (r2 >= 1 && o + (a[b[r2]] & Mod) >= (1 << (k + 2)) - 1) r2--;
			if (max(i + 1, l1) <= r1) cnt += r1 - max(i + 1, l1) + 1;
			if (max(i + 1, l2) <= r2) cnt += r2 - max(i + 1, l2) + 1;
		}
		if (cnt & 1) ans |= 1 << k;
	}
	write(ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值