题目大意
求出 ⨁ i = 1 n gcd ( i , n ) \bigoplus\limits_{i=1}^{n} \gcd(i,n) i=1⨁ngcd(i,n) 的值。
题目解法
前置知识:
- 两个相同的数按位异或的结果是 0 0 0,即 a ⊕ a = 0 a \oplus a=0 a⊕a=0;
- 一个非 0 0 0 的数按位异或 0 0 0 的结果还是原来那个数,即 0 ⊕ a = a 0 \oplus a =a 0⊕a=a;
- 按位运算遵循交换律,即 a ⊕ b ⊕ c = a ⊕ c ⊕ b a \oplus b \oplus c=a \oplus c \oplus b a⊕b⊕c=a⊕c⊕b。
刚开始一看,想到了暴力。但是发现 n ≤ 1 0 18 n \le 10^{18} n≤1018,我就知道这题目大概率是一个结论题。但是我没有思路,于是就用暴力打了一个表。
#include<bits/stdc++.h>
using namespace std;
int main(){
for(int n=1;n<=1000;n++){
int ans=0;
for(int i=1;i<=n;i++) ans^=__gcd(i,n);
cout<<n<<":"<<ans<<"\n";
}
}
之后就很容易发现,当 n n n 为奇数时,结果就是 n n n。
这是为什么呢?这里用到了欧几里得算法,证明过程我就不写了,详情可以自行查看。
结论就是: gcd ( a , b ) = gcd ( b − a , b ) \gcd(a,b) = \gcd(b-a,b) gcd(a,b)=gcd(b−a,b),也就是 gcd ( i , n ) = gcd ( n − i , n ) \gcd(i,n) = \gcd(n-i,n) gcd(i,n)=gcd(n−i,n)。
因此,我们可以发现:
-
当 n n n 为奇数时,由 a ⊕ a = 0 a \oplus a=0 a⊕a=0 可以得出,前 n − 1 n-1 n−1 项会互相抵消(第 i i i 项和第 n − i n-i n−i 项抵消),最后只剩下第 n n n 项了,答案就是 0 ⊕ gcd ( n , n ) 0 \oplus \gcd(n,n) 0⊕gcd(n,n),由于 0 ⊕ a = a 0 \oplus a=a 0⊕a=a 以及 gcd ( a , a ) = a \gcd(a,a)=a gcd(a,a)=a 我们可以得出答案就是 n n n;
-
当 n n n 为偶数时,我们可以发现,前 n 2 − 1 \dfrac{n}{2}-1 2n−1 项和第 n 2 + 1 ∼ n − 1 \dfrac{n}{2}+1 \sim n-1 2n+1∼n−1 项可以互相抵消,剩下的第 n 2 \dfrac{n}{2} 2n 项和第 n n n 项按位异或就是答案了。
参考代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
int t,n;
cin>>t ;
while(t--){
cin>>n;
if(n%2!=0) cout<<n<<endl;
else cout<<(n/2^n)<<endl;
}
}
2024年第一篇题解,祝大家新年快乐!