UVA 12716 GCD等于XOR[数学][提高+/省选-]

UVA 12716 GCD等于XOR[数学] [提高+/省选-]

GCD等于XOR

输入数据组数t,

接下来t行每行给定一个数字n,

如样例所示格式输出

满足\(1 \le b \le a \le n\)\(gcd(a,b)==a \oplus b\)\((a,b)\)二元组个数。

in

2
7
20000000

out

Case 1: 4
Case 2: 34866117

思路

首先想想暴力

也就是 if(gcd(a,b)==a^b)ans++

枚举每一个 \(a\)\(b\)

然后进行判断 这样的时间复杂度是 \(O(n^2)\)

看了看数据范围只能作罢

那么如何去优化呢

\(gcd(a,b)=a \oplus b= c\)

根据异或的交换律我们可以知道

\(a \oplus b= c , a \oplus c= b\)

因为\(gcd(a,b)= c\)

所以 \(c\) 一定是 \(a\)\(b\) 的因子

那么我们可以枚举 \(a\) 的因子\(c\)

那么 \(b\) 就是\(a \oplus c\)

再验证 gcd(a,b)是否等于 \(c\)

这样的时间复杂度是 \(O(nlog^2n)\)

已经可以解决这道问题了

那么还有没有更好的方法呢

通过观察我们可以发现

\(n\) = 7时

有4对成立 (3,2) (5,4) (6,4) (7,6)

我们发现 当\(gcd(a,b)==a \oplus b\) 时,总有 \(a-b=gcd(a,b)\) 成立

那么是不是总有这个规律呢

我们还是设 \(c\)\(a \oplus b\)\(gcd(a,b)\) 的结果

我们可以证明 $a-b \le a \oplus b $ (如不了解可以看文末)

又因为 \(c\)\(a\)\(b\) 的最小公因数

那么由辗转相除法我们可以类推出

\(gcd(a,b)\) \(\le\) \(a-b\)

也就是

\(gcd(a,b)\) \(\le\) \(a-b \le a \oplus b\)

\(c\) = \(a \oplus b\) = \(gcd(a,b)\)

也就是

\(c\) \(\le\) \(a-b \le c\)

也就是 \(a-b = c\)

也就是 $a-b = a \oplus b $

由于 gcd() 函数的时间复杂度 是\(O(logn)\)

\(\oplus\)的时间复杂度 是\(O(1)\)

那么我们只需要判断 \(a\)减去一个因子等不等于异或上这个因子

整个问题便变成了 \(O(nlogn)\) 的时间复杂度了

key code

const int N=3e7+10;
int n,m;
int ans[N];
int __;
void solve(){
	//try it again.
	cin>>n;
	cout<<ans[n]<<endl;
}
signed main(){
	IOS;
	int k=N>>1;
	fup(b,1,k){
		for(int a=b+b;a<=N;a+=b){
			if((a^b)==a-b){
				ans[a]++;
			}
		}
	}
	up(2,N)ans[o]+=ans[o-1];
	cin>>__;
	up(1,__){
		cout<<"Case "<<o<<": ";
		solve();
	}
    return 0;
}

证明 $a-b \le a \oplus b $

当 $ a $ 是 1010 1111 ,$ b $ 是 1010 1111

这样的时候

此时 \(b\) 的每一位都在 \(a\) 的二进制上实现了相应的减法

也就是 $a-b = a \oplus b $ 的情况

如果有一位 \(a\)\(b\) 不相等的话

那么 \(b\) 的那一位便会在 \(a\) 上实现相应的加法

也就是 $a-b < a \oplus b $ 的情况

不存在 $a-b > a \oplus b $ 的情况

posted @ 2023-02-28 17:28  liangqianxing  阅读(46)  评论(0)    收藏  举报