题目链接:
题目大意:
快速求:
\[\sum_{i=1}^{n}\sum_{i=1}^{m}\left[\operatorname{gcd}(i,j)==d\right] \]
正文:
将式子化简:
\[\begin{aligned}\sum_{i=1}^{n}\sum_{i=1}^{m}\left[\operatorname{gcd}(i,j)==d\right] &= \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}\left[\operatorname{gcd}(i,j)==1\right]\\ &=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{k|\operatorname{gcd}(i,j)}\mu(k)\end{aligned} \]
把 \(\mu\) 那儿移到前面:
\[\begin{aligned}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{i=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{k|\operatorname{gcd}(i,j)}\mu(k) &= \sum_{k=1}\mu(k)\sum_{k|i}^{\lfloor\frac{n}{d}\rfloor}\sum_{k|j}^{\lfloor\frac{m}{d}\rfloor}1\\ &=\sum_{k=1}\mu(k)\left\lfloor\frac{n}{kd}\right\rfloor\left\lfloor\frac{m}{kd}\right\rfloor\end{aligned} \]
接着预处理一下 \(\mu\) 函数再求个关于 \(\left\lfloor\frac{n}{kd}\right\rfloor\left\lfloor\frac{m}{kd}\right\rfloor\) 的 整除分块 就行了。
代码:
ll n, m, d, t;
ll ans;
ll pri[N], miu[N], cnt, sum[N];
bool vis[N];
void prework()
{
miu[1] = 1;
for (int i = 2; i <= N - 10; i++)
{
if(!vis[i]) {pri[++cnt] = i, miu[i] = -1;}
for (int j = 1; j <= cnt && pri[j] * i <= N - 10; j++)
{
vis[pri[j] * i] = 1;
if (i % pri[j] == 0)
{
miu[i * pri[j]] = 0;
break;
}
else
miu[i * pri[j]] = -miu[i];
}
}
for (int i = 1; i <= N - 10; i++)
sum[i] = sum[i - 1] + miu[i];
}
int main()
{
prework();
for (scanf ("%lld", &t); t--; )
{
ans = 0LL;
scanf("%lld%lld%lld", &n, &m, &d);
if(n > m)
{
int c = n; n = m; m = c;
}
n /= d, m /= d;
for (int l = 1, r; l <= n; l = r + 1)
{
r = min (n / (n / l), m / (m / l));
ans += (sum[r] - sum[l - 1]) * (n / l) * (m / l);
}
printf ("%lld\n", ans);
}
return 0;
}