原题解链接:https://ac.nowcoder.com/discuss/154293
默认
更换枚举顺序,先枚举 ,原式化为
将同时除以
设,则
设
首先筛出 ,然后可以在的时间内预处理出 的前缀积
可以在线性筛的过程中计算
取值有 种,所以每次询问可以 回答
总复杂度
#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;
}