Description
D
o
r
i
s
Doris
Doris刚刚学习了
F
i
b
o
n
a
c
c
i
Fibonacci
Fibonacci数列。用
f
[
i
]
f[i]
f[i]表示数列的第i项,那么
f
[
0
]
=
0
,
f
[
1
]
=
1
,
f
[
n
]
=
f
[
n
−
1
]
+
f
[
n
−
2
]
,
n
>
=
2
f[0]=0 ,f[1]=1 ,f[n]=f[n-1]+f[n-2],n>=2
f[0]=0,f[1]=1,f[n]=f[n−1]+f[n−2],n>=2
D
o
r
i
s
Doris
Doris用老师的超级计算机生成了一个
n
×
m
n×m
n×m的表格,第
i
i
i行第
j
j
j列的格子中的数是
f
[
g
c
d
(
i
,
j
)
]
f[gcd(i,j)]
f[gcd(i,j)],其中
g
c
d
(
i
,
j
)
gcd(i,j)
gcd(i,j)表示
i
,
j
i,j
i,j的最大公约数。
D
o
r
i
s
Doris
Doris的表格中共有
n
×
m
n×m
n×m个数,她想知道这些数的乘积是多少。答案对
1
0
9
+
7
10^9+7
109+7取模。
Sample Input
3
2 3
4 5
6 7
Sample Output
1
6
960
莫反一下:
∏
d
=
1
n
f
(
d
)
∑
i
=
1
n
d
∑
j
=
1
m
d
∑
k
∣
i
,
k
∣
j
μ
(
k
)
\prod_{d=1}^nf(d)^{\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac md}\sum_{k|i,k|j}\mu(k)}
d=1∏nf(d)∑i=1dn∑j=1dm∑k∣i,k∣jμ(k)
=
>
=>
=>
∏
d
=
1
n
f
(
d
)
∑
k
=
1
n
d
μ
(
k
)
⌊
n
k
d
⌋
⌊
m
k
d
⌋
\prod_{d=1}^nf(d)^{\sum_{k=1}^{\frac nd}\mu(k)\lfloor \frac n{kd}\rfloor\lfloor \frac m{kd}\rfloor}
d=1∏nf(d)∑k=1dnμ(k)⌊kdn⌋⌊kdm⌋
然后用一个老套路,设
T
=
k
d
T=kd
T=kd
∏
T
=
1
n
f
(
d
)
(
∏
d
∣
T
f
(
d
)
μ
(
T
d
)
)
⌊
n
T
⌋
⌊
m
T
⌋
\prod_{T=1}^n f(d)(\prod_{d|T}f(d)^{\mu(\frac Td)})^{\lfloor \frac nT\rfloor\lfloor \frac mT\rfloor}
T=1∏nf(d)(d∣T∏f(d)μ(dT))⌊Tn⌋⌊Tm⌋
中间的式子可以
O
(
n
∗
l
o
g
n
)
O(n*logn)
O(n∗logn)预处理,然后数论分块搞一下时间复杂度就是
O
(
T
∗
s
q
r
t
n
∗
l
o
g
m
o
d
)
O(T*sqrtn*logmod)
O(T∗sqrtn∗logmod)
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const int mod = 1e9 + 7;
const int N = 1000001;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
bool v[N];
int plen, mu[N], p[N], f[N], inv[N];
LL s[N];
int add(int x, int y) {
x += y;
return x >= mod ? x - mod : x;
}
LL pow_mod(LL a, LL k) {
LL ans = 1;
while(k) {
if(k & 1) (ans *= a) %= mod;
(a *= a) %= mod; k /= 2;
} return ans;
}
void get_p() {
mu[1] = s[1] = s[0] = 1;
for(int i = 2; i < N; i++) {
if(!v[i]) p[++plen] = i, mu[i] = -1;
for(int j = 1; j <= plen && (LL)i * p[j] < N; j++) {
v[i * p[j]] = 1;
if(i % p[j] == 0) {mu[i * p[j]] = 0; break;}
else mu[i * p[j]] = -mu[i];
} s[i] = 1;
}
}
int main() {
get_p();
f[0] = 0, f[1] = 1, inv[1] = 1;
for(int i = 2; i < N; i++) f[i] = add(f[i - 1], f[i - 2]), inv[i] = pow_mod(f[i], mod - 2);
for(int i = 1; i < N; i++) {
for(int j = i, o = 1; j < N; j += i, ++o) {
(s[j] *= mu[o] == -1 ? inv[i] : pow_mod(f[i], mu[o])) %= mod;
}
} for(int i = 1; i < N; i++) (s[i] *= s[i - 1]) %= mod;
int tt = read();
while(tt--) {
int n = read(), m = read();
if(n > m) swap(n, m); LL ans = 1;
for(int l = 1, r; l <= n; l = r + 1) {
r = _min(n / (n / l), m / (m / l));
LL hh = s[r] * pow_mod(s[l - 1], mod - 2) % mod;
(ans *= pow_mod(hh, (LL)(n / l) * (m / l) % (mod - 1))) %= mod;
} put(ans), puts("");
} return 0;
}