前言

这nm sb hexo 我{{...}} 这种情况报错改了调了一个多小时

正文

人话版本:

Πi=1nΠj=1mf(gcd(i,j))\large \operatorname{\Pi}_{i=1}^{n}\limits\operatorname{\Pi}_{j=1}^{m}\limits f(\gcd(i,j))

我们转化一下,先枚举 gcd\gcd

Πd=1nΠi=1ndΠj=1mdf(d)ϵ(gcd(i,j))\large\operatorname{\Pi}_{d=1}^{n}\limits\operatorname{\Pi}_{i=1}^{\lfloor\frac{n}{d}\rfloor}\limits\operatorname{\Pi}_{j=1}^{\lfloor\frac{m}{d}\rfloor}\limits f(d)^{\epsilon(\gcd(i,j))}

把乘法放在指数上

Πd=1nf(d)i=1ndj=1mdϵ(gcd(i,j))\large \operatorname{\Pi}_{d=1}^{n}\limits f(d)^{\operatorname{\sum}_{i=1}^{\lfloor\frac{n}{d}\rfloor}\limits\operatorname{\sum}_{j=1}^{\lfloor\frac{m}{d}\rfloor}\limits \epsilon(\gcd(i,j))}

然后反演 μ\mu 函数

$ \large \operatorname{\Pi}{d=1}^{n}\limits f(d)^{\operatorname{\sum}{k=1}^{\lfloor\frac{m}{d}\rfloor}\limits\operatorname{\sum}{i=1}^{\lfloor\frac{n}{kd}\rfloor}\limits\operatorname{\sum}{j=1}^{\lfloor\frac{m}{kd}\rfloor}\limits \mu(k)}$

然后移出来

$ \large \operatorname{\Pi}{d=1}^{n}\limits \operatorname{\Pi}{k=1}^{\lfloor\frac{m}{d}\rfloor}\limits f(d)^{\mu(k) \operatorname{\sum}{i=1}^{\lfloor\frac{n}{kd}\rfloor}\limits\operatorname{\sum}{j=1}^{\lfloor\frac{m}{kd}\rfloor}\limits }$

kd=Tkd=T

可以得到

$ \large \operatorname{\Pi}{T=1}^{n}\limits \operatorname{\Pi}{d|T}^{}\limits f(d)^{\mu(\frac{T}{d}) \operatorname{\sum}{i=1}^{\lfloor\frac{n}{T}\rfloor}\limits\operatorname{\sum}{j=1}^{\lfloor\frac{m}{T}\rfloor}\limits }$

可以 O(nlogn)O(n \log n) 地预处理

ΠdTf(d)μ(Td)\operatorname{\Pi}_{d|T}^{}\limits f(d)^{\mu(\frac{T}{d}) }

然后外面就是个整除分块,然后做完了,记得预处理逆元,不然复杂度可能会假

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include<stdio.h>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>
#include<algorithm>

#define int long long

using namespace std;

const int maxn=1001000;
const int modp=1e9+7;
const int loopn=1e6;

int mu[maxn],p[maxn],inp[maxn],cnt;
int f[maxn],tc[maxn],n,m;
int _f[maxn],tmp[maxn];

int ksm(int x,int y)
{
int ans=1;
while(y)
{
if(y&1) ans=ans*x%modp;
x=x*x%modp;
y>>=1;
}
return ans;
}

inline void _prework(int n)
{
int i,j;
mu[1]=1;
for(i=2;i<=n;i++)
{
if(!inp[i]) p[++cnt]=i,mu[i]=-1;
for(j=1;j<=cnt&&i*p[j]<=n;j++)
{
inp[i*p[j]]=1;
if(i%p[j]==0)
{
mu[i*p[j]]=0;
break;
}
mu[i*p[j]]=-mu[i];
}
}
f[1]=f[2]=1;
for(i=3;i<=n;i++) f[i]=(f[i-1]+f[i-2])>modp?f[i-2]+f[i-1]-modp:f[i-1]+f[i-2];
for(i=1;i<=n;i++) tmp[i]=1,_f[i]=ksm(f[i],modp-2);
for(i=1;i<=n;i++)
for(j=1;i*j<=n;j++)
{
if(mu[j]>=0) tmp[i*j]=tmp[i*j]*ksm(f[i],mu[j])%modp;
else tmp[i*j]=tmp[i*j]*_f[i]%modp;
}
for(i=1;i<=n;i++) f[i]=tmp[i];
f[0]=1; _f[0]=1;
for(i=1;i<=n;i++) f[i]=(f[i]*f[i-1])%modp,_f[i]=ksm(f[i],modp-2);
}

inline void getans(int n,int m)
{
int i,j,ans=1;
for(i=1;i<=min(n,m);i=j+1)
{
j=min(n/(n/i),m/(m/i));
ans=ans*ksm((f[j]*_f[i-1])%modp,(n/i)*(m/i)%(modp-1))%modp;
}
cout<<ans<<endl;
}

signed main()
{
ios::sync_with_stdio(false);
register int i,j;
_prework(loopn);
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
getans(n,m);
}
return 0;
}