主要思路
这道题是一道很好的题,包含了数论里面的很多技巧。
首先,这是一道多组询问的题,询问数量非常的大,遂放弃使用欧拉函数来求。考虑可以使用莫比乌斯函数的性质来搞,开始从这方面分析。
复习一下莫比乌斯函数的定义:
\[ \mu(x) = \begin{cases} 0, 在x中存在指数大于一的质因子 \\ 1, 在x中质因子指数都为1且质因子个数为偶数 \\ -1, 在x中质因子质数都为1且质因子个数为奇数 \end{cases} \]
我们观察一下答案式子:\(\sum_{i,j} [gcd(x,y)=d]\)。我们先把\(gcd\)部分进行变换:
\[gcd(\frac{x}{d}, \frac{y}{d}) = 1\]
显然,这样的对数为\( \lfloor \frac{x}{d} \rfloor*\lfloor \frac{y}{d} \rfloor \)。我们考虑容斥:因为如果暴力累加的话,会多出很多不该存在的部分,比如说又是2的倍数又是3的倍数的部分。
所以最后答案式为:
\[\sum_{i=1}^{min\{a,b\}} \mu(i)*\lfloor \frac{x}{i} \rfloor*\lfloor \frac{y}{i} \rfloor \]
这时有个技巧,我们可以证明在整数段\([x, min\{ \lfloor \frac{a}{\lfloor \frac{a}{x} \rfloor} \rfloor, \lfloor \frac{b}{\lfloor \frac{b}{x} \rfloor} \rfloor \} ]\)上,\(\lfloor \frac{x}{i} \rfloor*\lfloor \frac{y}{i} \rfloor\)的结果是一样的,直接前缀和与之相乘即可。最后这样的段最坏情况为\(O(\sqrt{a}+\sqrt{b})\),所以时间复杂度比较低。
代码
// BZ1101.cpp #include <bits/stdc++.h> #define ll int using namespace std; const int MAX_N = 5e4 + 200; ll mobi[MAX_N], sum[MAX_N], n; bool vis[MAX_N]; int main() { for (int i = 1; i < MAX_N; i++) mobi[i] = 1; for (int i = 2; i < MAX_N; i++) { if (vis[i]) continue; mobi[i] = -1; for (int j = 2; i * j < MAX_N; j++) { vis[i * j] = true; if (j % i == 0) mobi[i * j] = 0; else mobi[i * j] *= -1; } } for (int i = 1; i < MAX_N; i++) sum[i] = sum[i - 1] + mobi[i]; scanf("%d", &n); while (n--) { int a, b, k, gx; scanf("%d%d%d", &a, &b, &k); a /= k, b /= k; int ans = 0; for (int i = 1; i <= min(a, b); i = gx + 1) { gx = min(a / (a / i), b / (b / i)); ans += (sum[gx] - sum[i - 1]) * (a / i) * (b / i); } printf("%d\n", ans); } return 0; }