知識點:莫比烏斯反演git
學到了 \(\prod\) 的交換。
另外莫比烏斯反演的代碼真好寫(
只用預處理一噸東西就作完了(spa
原題面:Luogu,時限 5s 的 Loj。code
設 \(f_{i}\) 表示斐波那契數列的第 \(i\) 項。
\(T\) 組數據,每次給定參數 \(n,m\),求:對象\[\prod_{i=1}^{n}\prod_{j=1}^{m}f_{\gcd(i,j)} \pmod {10^9 + 7} \]\(1\le T\le 10^3\),\(1\le n,m\le 10^6\)。
2S~3S,128MB。get
這裏的時限是 Luogu 的時限,須要略微卡常才能過。
不想卡常能夠移步 Loj。string
如下欽定 \(n\ge m\)。
大力化式子,先套路地枚舉 \(\gcd(i,j)\),用初中知識把兩個 \(\prod\) 化到指數位置,原式等於:it
分母套路一波,有:io
代回原式,原式等於:class
考慮再暴力拆一波,原式等於:變量
作不動了,但發現變量僅有 \(k,d,kd\),考慮更換枚舉對象改成枚舉 \(t = kd\) 與 \(d\),則原式等於:
枚舉對象變成了約數形式。從後面的式子推前面的式子是比較顯然的,能夠認爲這種枚舉 \(t=kd\) 的形式是一種逆向操做。
設:
\(g(t)\) 能夠用相似埃氏篩的方法 \(O(n\log n)\) 地預處理出來。再把 \(g\) 代回原式,原式等於:
能夠考慮預處理 \(g(t)\) 的前綴積,數論分塊枚舉指數求解便可。
總時間複雜度 \(O(n\log n + T\sqrt n)\),輕微卡常,多預處理一些東西能夠過。
//知識點:莫比烏斯反演 /* By:Luckyblock */ #include <algorithm> #include <cctype> #include <cstdio> #include <cstring> #define LL long long const LL mod = 1e9 + 7; const int kN = 1e6; //============================================================= LL n, m, ans; int p_num, p[kN + 10]; bool vis[kN + 10]; LL mu[kN + 10], f[kN + 10], g[kN + 10], prod[kN + 10]; LL invf[kN + 10], invp[kN]; //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1; for (; isdigit(ch); ch = getchar()) { w = (w << 3) + (w << 1) + (ch ^ '0'); } return f * w; } void Chkmax(int &fir_, int sec_) { if (sec_ > fir_) fir_ = sec_; } void Chkmin(int &fir_, int sec_) { if (sec_ < fir_) fir_ = sec_; } LL QPow(LL x_, LL y_) { x_ %= mod; LL ret = 1; for (; y_; y_ >>= 1ll) { if (y_ & 1) ret = ret * x_ % mod; x_ = x_ * x_ % mod; } return ret; } void Euler() { vis[1] = true, mu[1] = 1; for (int i = 2; i <= kN; ++ i) { if (! vis[i]) { p[++ p_num] = i; mu[i] = -1; } for (int j = 1; j <= p_num && i * p[j] <= kN; ++ j) { vis[i * p[j]] = true; if (i % p[j] == 0) { mu[i * p[j]] = 0; break; } mu[i * p[j]] = -mu[i]; } } } void Prepare() { g[1] = g[2] = 1; f[1] = f[2] = 1; invf[1] = invf[2] = 1; for (int i = 3; i <= kN; ++ i) { g[i] = 1; f[i] = (f[i - 1] + f[i - 2]) % mod; invf[i] = QPow(f[i], mod - 2); } Euler(); for (int d = 1; d <= kN; ++ d) { for (int j = 1; d * j <= kN; ++ j) { if (mu[j] == 1) { g[d * j] = g[d * j] * f[d] % mod; } else if (mu[j] == -1) { g[d * j] = g[d * j] * invf[d] % mod; } } } invp[0] = prod[0] = 1; for (int i = 1; i <= kN; ++ i) { prod[i] = prod[i - 1] * g[i] % mod; invp[i] = QPow(prod[i], mod - 2); } } //============================================================= int main() { Prepare(); int T = read(); while (T -- ){ n = read(), m = read(), ans = 1; if (n < m) std::swap(n, m); for (LL l = 1, r = 1; l <= m; l = r + 1) { r = std::min(n / (n / l), m / (m / l)); ans = (ans * QPow(prod[r] * invp[l - 1] % mod, 1ll * (n / l) * (m / l))) % mod; } printf("%lld\n", ans); } return 0; }