Processing math: 100%

zhugezy

codeforces 1323D 题解(数学)

codeforces 1323D 题解

UPD1: 应为0ai,aj<2p+1而不是0ai,aj<2p,与之相关的错误也已修正,如果还有错请直接评论区开喷。

题意:给n个数a1,a2,...,an,计算i<j(ai+aj)是异或。

n400000,1ai107

按二进制位考虑,从低位往高位看,最低位记作第0位,以此往上。考虑第p位是0还是1:第p位是1,当且仅当有奇数对i,j使得ai+aj的第p位是1。由于加法运算的高位不会影响低位,那就干脆忽视高位,只看第p位及以下的位。忽视高位后(也就是把数都%2p+1后),显然有0ai,aj<2p+1,那么0ai+aj<2p+2。因此ai+aj的第p位是1,当且仅当2pai+aj<2p+12p+1+2pai+aj

那么可以枚举i,查询有多少个j使得2pai+aj<2p+12p+1+2pai+aj。换句话说,查询有多少个aj[2pai,2p+1ai)[2p+1+2pai,+)

那么把数组排序,二分找到这些端点的位置就可以轻松统计出个数了。当然,还有一些细节,比如ij,还有每对数被算了两遍什么的,要慢慢去处理。

A=nmaxi=1(ai),时间复杂度O(n logn logA)。如果用双指针(当然这里有好多指针),能降低到O(n logA)。(我没有实际写这个双指针代码,如果无法做到请直接评论区开喷(

PS:我在赛中写的是O((n+2A) log2A)的,因为我没想到排序二分,就直接O(2A)打前缀和表了,但还是1400ms过了。。。感谢出题人爸爸不杀之恩

//O(n+2A log2A)的
#include <bits/stdc++.h>
#define LL long long
#define pb push_back
#define eb emplace_back
#define pii pair<int,int>
#define pll pair<LL,LL>
using namespace std;

int n, a[400008], cnt[20000008], v[400008];
int ans[32];
int fans = 0;
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &a[i]);
	}
	for (int i = 0; i < 25; ++i)
	{
		//cout << "i = " << i << endl;
		for (int j = 1; j <= n; ++j)
		{
			v[j] += (a[j] & (1 << i));
		}
		memset(cnt, 0, sizeof(cnt));
		for (int j = 1; j <= n; ++j)
		{
			cnt[v[j]]++;
		}
		for (int val = 1; val <= 20000000; ++val)
		{
			cnt[val] += cnt[val - 1];
		}
		for (int j = 1; j <= n; ++j)
		{
			//cout << "j = " << j << endl;
			int l = ((1 << i) - v[j]), r = ((1 << (i + 1)) - 1 - v[j]);
			int l2 = (1 << (i + 1)) + (1 << i) - v[j];
			//cout << l << "  " << r << endl;
			if (l - 1 >= 0)
				ans[i] += cnt[min(r, 20000000)] - cnt[l - 1] - (v[j] >= l && v[j] <= r);
			else
				ans[i] += cnt[min(r, 20000000)] - (v[j] >= l && v[j] <= r);
			/*if (l - 1 >= 0)
				cout << cnt[min(r, 20000000)] - cnt[l - 1] - (v[j] >= l && v[j] <= r) << endl;
			else
				cout << cnt[min(r, 20000000)] - (v[j] >= l && v[j] <= r) << endl;*/
			if (l2 >= r + 1)
				ans[i] += n - cnt[min(r + (1 << i), 20000000)] - (v[j] >= l2);
		}
		ans[i] /= 2;
		//cout << ans[i] << endl;
		if (ans[i] % 2)
			fans += (1 << i);
	}
	cout << fans << endl;
}

后记

感觉自己很无敌,但其实看来这题放在真的现场赛中也就是个银牌题中比较简单的题目,不知道为什么cf div2比赛中只有几十个人过,大概年轻人还是要多学习一个

posted on   zhugezy  阅读(188)  评论(3编辑  收藏  举报

编辑推荐:
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
阅读排行:
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

导航

统计

点击右上角即可分享
微信分享提示