P6860 象棋与马 杜教筛
题意
有一个无限大的棋盘,有一个马最初在((0,0)),它的每步可以走一个(a imes b)的矩形,即能够走到((x pm a,y pm b),或者(x pm b,y pm a))
若马通过上述移动方式可以达到棋盘中任意一点,那么(p(a,b) = 1),否则(p(a,b) = 0)
给出(T)组询问,每组询问会给出一个正整数(n),求出
[(sum_{a=1}^nsum_{b=1}^np(a,b))mod2^{64}
]
[n imes T leq 10^{11}\
T leq 5
]
分析
走到棋盘的充要条件是能够走到((1,0))
如果不能走到((1,0)),显然无法走到棋盘的任一点,如果能走到((1,0)),显然可以走到棋盘的任意位置
由于只有本质不同的4种走法
- ((a,b))
- ((b,a))
- ((-a,b))
- ((-b,a))
走到((1,0))的充要条件是
[x_1 cdot a + x_2 cdot b - y_1 cdot a - y_2 cdot b = 1\
x_1 cdot b + x_2 cdot a + y_1 cdot b + y_2 cdot a = 0
]
上下相加,有
[(x_1+ x_2 - (y_1 - y_2)) a + (x_1 + x_2 + (y_1 - y_2))b = 1
]
即
[(x - y)a + (x + y) b = 1
]
可见
[(a,b) = 1\
]
由于$(x + y) (与)(x - y)$必奇偶性同,且必全为奇数,若是偶数,显然右边不等于1
可以得出a,b奇偶性不同,若相同,右边不等于0
下面进行对答案讨论
若(a)为偶数,只需要求出为奇数且与(a)互质的数,答案显然是(phi(a))
若(a)为奇数,只需要求出为偶数且与(a)互质的数,答案为(frac{phi(a)}{2}),这是因为,(a)为奇数时,与它互质的数总是成对出现的
这是发现答案就是
[ans = sumphi(i) + sum_{i 为偶数}phi(i)
]
由于(n)达到1e11,这就成为了杜教筛的模板题
至于后面那一坨,考虑用递归式处理
[S(n) = sum phi(i)\
ans(n) = S(n) + ans(n / 2)
]
用到的欧拉函数性质
[a \% 2 == 1,phi(2a) = phi(a)\
a \% 2== 0,phi(2a) = 2phi(a)
]
代码
map<ull, ull> Sphi;
const int M = 1e7 + 5;
ull prime[M], vis[M], phi[M], s[M], n, m;
void init() {
phi[1] = 1;
for (re int i = 2; i <= M - 5; i++) {
if (!vis[i]) {
vis[i] = i;
prime[++m] = i;
phi[i] = i - 1;
}
for (re int j = 1; j <= m && prime[j] *i <= M - 5; j++) {
if (prime[j] > vis[i]) break;
vis[i * prime[j]] = prime[j];
phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
}
}
for (re int i = 1; i <= M - 5; i++) {
if (i & 1) s[i] = phi[i << 1] / 2;
else s[i] = phi[i];
s[i] += s[i - 1];
phi[i] += phi[i - 1];
}
}
ull getphi(ull n) {
if (n <= M - 5)return phi[n];
if (Sphi[n]) return Sphi[n];
ull res = 0;
if (n % 2 == 0) res = n / 2 * (n + 1);
else res = (n + 1) / 2 * n;
for (ull l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
res -= (r - l + 1) * getphi(n / l);
}
return Sphi[n] = res;
}
ull S(ull n) {
if (n <= 1) return 0;
return getphi(n) + S(n / 2);
}
int main() {
init();
int T = readint();
while (T--) {
n = readull();
printf("%llu
", S(n));
}
}