[prod_{i=1}^{n} prod_{j=1}^{m} f_{gcd(i,j)}\
=prod_{d=1}^{n}f_d^{sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)==d]}\
]
[sum_{i=1}^{n}sum_{j=1}^{m}[gcd(i,j)==d]\
=sum_{i=1}^{frac{n}{d}}sum_{j=1}^{frac{m}{d}} [gcd(i,j)==1]\
=sum_{i=1}^{frac{n}{d}}sum_{j=1}^{frac{m}{d}}sum_{x|gcd(i,j)}mu(x)\
=sum_{x=1}^{frac{n}{d}}mu(x)dfrac{n}{dx}dfrac{m}{dx}
]
[=prod_{d=1}^{n}f_d^{sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)==d]}\
=prod_{d=1}^{n}f_d^{sumlimits_{x=1}^{frac{n}{d}}mu(x)frac{n}{dx}frac{m}{dx}}\
=prod_{d=1}^{n}f_d^{sumlimits_{T=1,d|T}^{n}mu(frac{T}{d})frac{n}{T}frac{m}{T}}\
=prod_{T=1}^{n}prod_{d|T}^{n}f_d^{mu(frac{T}{d})frac{n}{T}frac{m}{T}}\
=prod_{T=1}^{n}left(prod_{d|T}^{n}f_d^{mu(frac{T}{d})}
ight)^{frac{n}{T}frac{m}{T}}\
]
(O(nlog n)) 预处理出 (f_i) 的逆元就可以 (O(nln n)) 筛出 (g(T)=prodlimits_{d|T}^{n}f_d^{mu(frac{T}{d})}) 了。
询问的时候整除分块加个快速幂即可,时间复杂度 (O(nlog mod+nln n+qsqrt{n}log mod))
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int mod = 1e9 + 7;
int T, n, m;
const int N = 1e6 + 5;
int ivb[N], mu[N], fib[N], pri[N], cnt, f[N];
bool vis[N];
int qpow(int n, int k, int res = 1) {
for(;k; k >>= 1, n = 1ll * n * n % mod)
if (k & 1)res = 1ll * res * n % mod;
return res;
}
int power(int n, int k){
if (k == -1) return ivb[n];
if (k == 0) return 1;
if (k == 1) return fib[n];
}
void init(const int&N) {
fib[1] = 1, mu[1] = 1, ivb[1] = 1;
for (int i = 2; i <= N; ++ i) fib[i] = (fib[i - 1] + fib[i - 2]) % mod, ivb[i] = qpow(fib[i], mod - 2);
for (int i = 2; i <= N; ++ i) {
if(!vis[i]) pri[++ cnt] = i, mu[i] = -1;
for (int j = 1; j <= cnt && i * pri[j] <= N; ++ j) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
mu[i * pri[j]] = - mu[i];
}
}
for (int i = 0; i <= N; ++ i) f[i] = 1;
for (int i = 1; i <= N; ++ i)
for (int j = 1; i * j <= N; ++ j)
f[i * j] = 1ll * f[i * j] * power(i, mu[j]) % mod;
for (int i = 1; i <= N; ++ i) f[i] = 1ll * f[i] * f[i - 1] % mod;
}
int query(int n, int m){
if(n > m) n ^= m ^= n ^= m;
int res = 1;
for(int l = 1, r;l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
res = 1ll * res * qpow(1ll * f[r] * qpow(f[l - 1], mod - 2) % mod, 1ll * (n / l) * (m / l) % (mod - 1)) % mod;
}
return res;
}
signed main() {
init(N - 5);
T = read();
while(T --) {
n = read(), m = read();
printf("%d
",query(n,m));
}
}