BNUZOJ#1451 - XOR的性质

博客介绍了如何利用异或性质解决BNUZOJ中的问题,涉及目标是找出所有满足gcd(N,M)=N⊕M条件的整数M,其中N的最大值为10^10。通过分析,博主提出将搜索范围缩小到N的约数,使用异或性质N⊕gcd(N,M)=M来改进算法,从而避免了O(N)的时间复杂度。此外,还提及了一个与异或和最大公约数相关的性质gcd(a,b)≤∣a−b∣≤a⊕b。" 126468363,12715313,提升pip安装Python库速度:国内源解决方案,"['python', 'pip', '镜像源', '加速', '软件安装']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源

BNUZOJ (WeJudge) 1451

目标

输入正整数 N ( 1 ≤ N ≤ 1 0 10 ) N(1\leq N\leq 10^{10}) N(1N1010),找出所有满足 1 ≤ M ≤ N 1\leq M\leq N 1MN以及 gcd ⁡ ( N , M ) = N ⊕ M (1) \gcd(N,M)=N\oplus M\tag{1} gcd(N,M)=NM(1)的整数 M M M1. 程序运行的时间限制1s.

初步复杂度分析

由于 N N N最大可以到 1 0 10 10^{10} 1010,且原题是要求多组数据输入,不难看出 O ( N ) O(N) O(N)时间复杂度的算法很容易超时. 因此,直接按照题目意思枚举是不可行的. 由于涉及到 gcd ⁡ \gcd gcd函数,可以想象,如果能够将搜索范围缩小为 N N N的约数,那么就很有可能将复杂度降至 O ( N ) O(\sqrt{N}) O(N ),进而只需要大约 1 0 5 10^5 105级别的运算量.

异或的性质

此处就需要利用异或的一个性质:若 X ⊕ Y = Z X\oplus Y=Z XY=Z,则 X ⊕ Z = Y X\oplus Z=Y XZ=Y. 由这个性质, ( 1 ) (1) (1)式可以被改写为 N ⊕ gcd ⁡ ( N , M ) = M . (2) N\oplus\gcd(N,M)=M\tag{2}. Ngcd(N,M)=M.(2)
gcd ⁡ ( N , M ) ∣ N \gcd(N,M)\mid N gcd(N,M)N,因此相比于枚举 M M M然后求解 gcd ⁡ ( N , M ) \gcd(N,M) gcd(N,M)这样一个 O ( N ) O(N) O(N)的思路,反过来枚举所有 N N N的约数 a a a,然后利用 M = N ⊕ a M=N\oplus a M=Na计算出 M M M的值,再检查 a a a是否等于 gcd ⁡ ( N , M ) \gcd(N,M) gcd(N,M)效率更高. 如果检查通过,则找到了一个解. 该方法最多只需枚举 N N N的所有约数,这是 O ( N ) O(\sqrt{N}) O(N )就可以实现的. 这样,该问题就得到了解决. (代码见后文)

这个问题其实到这里就结束了. 不过,还有一条与异或、最大公约数有关的性质也值得在这里展示: gcd ⁡ ( a , b ) ≤ ∣ a − b ∣ ≤ a ⊕ b . (3) \gcd(a,b)\leq |a-b|\leq a\oplus b\tag{3}. gcd(a,b)abab.(3)
这个性质适用于所有以其正常二进制编码进行按位异或运算的正整数 a , b a,b a,b.

不等式的前半部分的说明用 gcd ⁡ \gcd gcd函数的基本性质即可实现:
不妨设 a > b a>b a>b. 设 c = gcd ⁡ ( a , b ) c=\gcd(a,b) c=gcd(a,b),则 a = m c , b = n c ( m , n ∈ N ∗ ) a=mc,b=nc(m,n\in\mathbf{N^*}) a=mc,b=nc(m,nN), ∣ a − b ∣ = a − b = ( m − n ) c |a-b|=a-b=(m-n)c ab=ab=(mn)c. 此处 m − n m-n mn必然大于等于 1 1 1,因此 gcd ⁡ ( a , b ) ≤ ∣ a − b ∣ \gcd(a,b)\leq|a-b| gcd(a,b)ab.

而后半部分则主要是基于按位异或运算可以等效于“无借位减法”的认识(其实同时也是“无进位加法”),此处就不给出数学意义上的严格证明。以下的真值表可以说明这一点:

X X X Y Y Y X ⊕ Y X\oplus Y XY difference ( X , Y ) \text{difference}(X,Y) difference(X,Y) borrow ( X , Y ) \text{borrow}(X,Y) borrow(X,Y)
00000
01111
10110
11000

UVa12716是一道与本题类似的问题,它的解法往往需要利用 ( 3 ) (3) (3)中提到的性质.

代码

#include <iostream>
#include <cmath>
#include <set>

long long gcd(long long a, long long b)
{
	return b == 0 ? a : gcd(b, a % b);
}

inline bool check(long long n, long long i)
{
	long long xor_res = n ^ i;
	if (xor_res >= 1 && xor_res <= n
		&& xor_res % i == 0 && gcd(xor_res, n) == i)
	{
		return true;
	}
	return false;
}

int main()
{
	using std::cin;
	cin.sync_with_stdio(false);
	cin.tie(nullptr);
	long long n;
	while (cin >> n)
	{
		std::set<long long> sst;
		int cnt = 0;
		for (int i = 1; i <= std::sqrt(n); i++)
		{
			if (n % i != 0)
			{
				continue;
			}
			if (check(n, i))
			{
				sst.insert(n ^ i);
			}
			if (n / i != i && check(n, n / i))
			{
				sst.insert(n ^ (n / i));
			}
		}
		std::cout << sst.size() << std::endl;
		if (sst.size())
		{
			auto it = sst.cbegin();
			std::cout << *it;
			it++;
			for (; it != sst.cend();
				it++)
			{
				std::cout << " " << *it;
			}
		}
		std::cout << std::endl;
	}

	return 0;
}

写在最后

本文提供的解题思路及程序代码仅供参考,并不保证能够通过特定Judger的评测,更不保证它们得到了充分的优化.


  1. gcd ⁡ ( m , n ) \gcd(m,n) gcd(m,n) m m m n n n的最大公约数,“ ⊕ \oplus ”为按位异或(bitwise XOR). ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值