异或约数和 [异或相关]

异或约数和


\color{blue}{最初想法}

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


\color{red}{正解部分}

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

g(x)={0    x   else+{1    N20    elseg(x)= \begin{cases} 0\ \ \ \ 奇数\\ x\ \ \ else \end{cases} +\begin{cases} 1 \ \ \ \ \lceil \frac{N}{2}\rceil为奇数 \\ 0 \ \ \ \ else\end{cases}

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


\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;
}
posted @ 2019-07-25 19:26  XXX_Zbr  阅读(150)  评论(0)    收藏  举报