异或约数和


<mstyle mathcolor="blue"> </mstyle> \color{blue}{最初想法}

[ 1 , x ] [1, x] [1,x] 内含有 x x x 这个约数的数个数为 c n t = N x cnt = \lfloor \frac{ N } { x } \rfloor cnt=xN,
c n t cnt cnt 为偶数时, 贡献为 0 0 0, 当 c n t cnt cnt 为奇数时, 对整体答案贡献为 异或 x x x,
枚举 x [ 1 , N ] x∈[1,N] x[1,N] 直接计算贡献, 复杂度 O ( N ) O(N) O(N) .
整除分块 加上类似 这里 的方法可以优化到 O ( N l o g N ) O(\sqrt{N}logN) O(N logN), 但是仍然不能 A C AC AC.


<mstyle mathcolor="red"> </mstyle> \color{red}{正解部分}

有一个规律, 设 g ( x ) g(x) g(x) [ 1 , x ] [1,x] [1,x] 内的异或和, 则

g ( x ) = { <mstyle displaystyle="false" scriptlevel="0"> 0 <mtext>      </mtext> </mstyle> <mstyle displaystyle="false" scriptlevel="0"> x <mtext>     </mtext> e l s e </mstyle> + { <mstyle displaystyle="false" scriptlevel="0"> 1 <mtext>      </mtext> N 2 </mstyle> <mstyle displaystyle="false" scriptlevel="0"> 0 <mtext>      </mtext> e l s e </mstyle> g(x)= \begin{cases} 0\ \ \ \ 奇数\\ x\ \ \ else \end{cases} +\begin{cases} 1 \ \ \ \ \lceil \frac{N}{2}\rceil为奇数 \\ 0 \ \ \ \ else\end{cases} g(x)={0    x   else+{1    2N0    else

于是前面需要 O ( l o g N ) O(logN) O(logN) 计算的只需要 O ( 1 ) O(1) O(1) 了, 总体复杂度 O ( N ) O(\sqrt{N}) O(N ) , 可以 A C AC AC .


<mstyle mathcolor="red"> </mstyle> \color{red}{实现部分}

没什么好说的 …

#include<bits/stdc++.h>
#define reg register
typedef long long ll;

ll N;
ll Ans;

ll Sum(ll x){
        if(!x) return 0;
        ll s_1, s_2;
        if(x & 1) s_1 = 0;
        else s_1 = x;
        ll tmp = (N-1)/x + 1;
        if(tmp & 1) s_2 = 1;
        else s_2 = 0;
        return s_1 + s_2;
}

int main(){
	scanf("%lld", &N);
	for(reg ll l = 1, r; l <= N; l = r+1){
		r = N/(N/l);
		if((N/l & 1) == 0) continue ;
		Ans ^= Sum(r) ^ Sum(l-1);
	}
        printf("%lld\n", Ans);
	return 0;
}