原题解链接:https://ac.nowcoder.com/discuss/154293

默认nm n \leq m

i=1nj=1mg(gcd(i,j))\prod_{i=1}^{n} \prod_{j=1}^{m} g(\operatorname{gcd}(i, j))

更换枚举顺序,先枚举gcd(i,j) \text{gcd}(i,j)​ ,原式化为

d=1ng(d)i=1nj=1m[gcd(i,j)=d]\prod_{d=1}^{n} g(d)^{\sum_{i=1}^{n} \sum_{j=1}^{m}[\operatorname{gcd}(i, j)=d]}

i,j i, j同时除以d d

=d=1ng(d)i=1mj=1m[gcd(i,j)=1]=\prod_{d=1}^{n} g(d)^{\left.\sum_{i=1}^{m} \sum_{j=1}^{m}\right\rfloor}[\operatorname{gcd}(i, j)=1]

=d=1ng(d)i=1ndj=1mkiλkjμ(k)=\prod_{d=1}^{n} g(d)^{\left.\sum_{i=1}^{n d} \sum_{j=1}^{m}\right\rfloor} \sum_{k i \lambda k j} \mu(k)

=d=1ng(d)k=1nμ(k)kdnkdm=\prod_{d=1}^{n} g(d)^{\sum_{k=1}^{n} \mu(k)\left\lfloor_{k d}^{n}\right\rfloor\left\lfloor_{k d}^{m}\right\rfloor}

T=kd T=kd,则

T=1n(dTg(d)μ(Td))TnTm\prod_{T=1}^{n}\left(\prod_{d \mid T} g(d)^{\mu\left(\frac{T}{d}\right)}\right)^{\left\lfloor_{T}^{n}\right\rfloor\left\lfloor_{T}^{m}\right\rfloor}

F(T)=dTg(d)μ(Td)F(T)=\prod_{d T} g(d)^{\mu\left(\frac{T}{d}\right)}

首先筛出 μ\mu ,然后可以在O(nlogn) O(nlogn)的时间内预处理出 F(T)F(T)的前缀积

g(d)g(d)​ 可以在线性筛的过程中计算

nTmT\left\lfloor\frac{n}{T}\right\rfloor\left\lfloor\frac{m}{T}\right\rfloor 取值有 O(n)O(\sqrt{n}) 种,所以每次询问可以 O(n)O(\sqrt{n}) 回答

总复杂度 O(nlogn+qn)O(n \log n+q \sqrt{n})

#include <bits/stdc++.h>
using namespace std;

typedef long long lo;

const lo mo = 1e9 + 7;
lo t, n, m, cnt, mu[250050], g[250050], inv[250050], f[250050], F[250050], prime[250050];

bool flag[250050];

lo ksm(lo m, lo n)
{
  m = m % mo;
  if (n > 0)
  {
    lo tmp = ksm(m, n / 2);
    if (n & 1) return (((tmp * tmp) % mo) * m) % mo;
    return (tmp * tmp) % mo;
  }
  return 1;
}
int main()
{
  flag[1] = mu[1] = f[1] = F[0] = F[1] = g[1] = inv[1] = 1; lo lin;
  for (int i = 2; i <= 250000; i ++)
  {
    f[i] = 1;
    if (flag[i] == 0)
      prime[++ cnt] = i, mu[i] = -1, g[i] = 1;
    inv[i] = ksm(g[i], mo - 2);
    for (int j = 1; j <= cnt && (lin = prime[j] * i) <= 250000; j ++)
    {
      flag[lin] = 1, g[lin] = g[i] + 1;
      if (i % prime[j] == 0)
      {
        mu[lin] = 0; break;
      }
      mu[lin] = - mu[i];
    }
  }
  for (int i = 1; i <= 250000; i ++)
  {
    if (mu[i] != 0)
      for (int j = i; j <= 250000; j += i)
        f[j] = f[j] * ((mu[i] == 1) ? g[j / i] : inv[j / i]) % mo;
    F[i] = F[i - 1] * f[i] % mo;
  }
  scanf("%lld", &t);
  while (t --)
  {
    lo ans = 1; scanf("%lld%lld", &n, &m); lin = 0;
    if (n > m)
      swap(n, m);
    for (int i = 1; i <= n; i = lin + 1)
    {
      lin = min(n / (n / i), m / (m / i));
      lo pre = F[lin] * ksm(F[i - 1], mo - 2) % mo;
      ans = ans * ksm(pre, (n / i) * (m / i)) % mo;
    }
    printf("%lld\n", ans);
  }
  return 0;
}