[bzoj4816][Sdoi2017]数字表格
题目大意:有$T(T\leqslant 1000)$组数据,每组数据给你$n,m(1\leqslant n,m \leqslant 10^6)$,求出$\displaystyle\prod\limits_{i=1}^n \displaystyle\prod\limits_{j=1}^m F[(i,j)]$($F(i)$为$fibonacci$数列第$i$项)
题解:下文中假设$n \leqslant m$
$$
\def\dprod{\displaystyle\prod\limits}\\
\def\dsum{\displaystyle\sum\limits}\\
\dprod_{i=1}^n\dprod_{j=1}^m F[(i,j)]=\dprod_{d=1}^n F(d)^{\sum_{i=1}^n\sum_{j=1}^m [(i,j)==d]}\\
令g(p)=\dsum_{i=1}^n\dsum_{j=1}^m [(i,j)==p]\\
\begin{align*}
令G(p)&=\dsum_{p|k}g(k)\\
&=\dsum_{p|k}\dsum_{i=1}^n\dsum_{j=1}^m [(i,j)==k]\\
&=\dsum_{i=1}^n\dsum_{j=1}^m [p|(i,j)]\\
&=\left\lfloor\dfrac{n}{p}\right\rfloor\cdot\left\lfloor\dfrac{m}{p}\right\rfloor
\end{align*}\\
$$
$$
\def\dsum{\displaystyle\sum\limits}\\
莫比乌斯反演得:\\
\begin{align*}
g(p)&=\dsum_{p|k}\mu\big(\dfrac{k}{p}\big)G(p)\\
&=\dsum_{p|k}\mu\big(\dfrac{k}{p}\big)\left\lfloor\dfrac{n}{p}\right\rfloor\cdot\left\lfloor\dfrac{m}{p}\right\rfloor\\
&=\dsum_{i=1}^n\mu(i)\left\lfloor\dfrac{n}{i\cdot p}\right\rfloor\cdot\left\lfloor\dfrac{m}{i\cdot p}\right\rfloor
\end{align*}
$$
$$
\def\dprod{\displaystyle\prod\limits}\\
\def\dsum{\displaystyle\sum\limits}\\
\begin{align*}
\dprod_{i=1}^n\dprod_{j=m}^m F[(i,j)]&=\dprod_{d=1}^n F(d)^{\sum_{i=1}^n\sum_{j=1}^m [(i,j)==d]}\\
&=\dprod_{d=1}^nF(d)^{g(d)}\\
&=\dprod_{d=1}^nF(d)^{\sum_{i=1}^n\mu(i)\lfloor\frac{n}{i p}\rfloor\cdot\lfloor\frac{m}{i p}\rfloor}\\
&=\dprod_{d=1}^n\dprod_{d|k}F(d)^{\mu\big(\dfrac{k}{d}\big)\big\lfloor\dfrac{n}{k}\big\rfloor\big\lfloor\dfrac{m}{k}\big\rfloor}\\
&=\dprod_{k=1}^n\bigg(\dprod_{d|k}F(d)^{\mu\big(\dfrac{k}{d}\big)}\bigg)^{\big\lfloor\dfrac{n}{k}\big\rfloor\big\lfloor\dfrac{m}{k}\big\rfloor}\\
\end{align*}\\
$$
$$
\def\dprod{\displaystyle\prod\limits}\\
令s[k]=\dprod_{d|k}F(d)^{\mu\big(\dfrac{k}{d}\big)}\\
预处理出s,然后整除分块就行了
$$
卡点:无
C++ Code:
#include <cstdio> #include <cstring> #define maxn 1000010 using namespace std; const int mod = 1000000007; int F[maxn], invF[maxn], s[maxn], invs[maxn]; int plist[maxn], miu[maxn], ptot; bool isp[maxn]; int pw(int base, int p) { base %= mod, p %= mod - 1; int ans = 1; for (; p; p >>= 1, base = 1ll * base * base % mod) if (p & 1) ans = 1ll * ans * base % mod; return ans; } int inv(int a) { return pw(a, mod - 2); } void sieve(int n) { invs[0] = s[0] = s[1] = 1; F[0] = 0; invF[1] = F[1] = miu[1] = 1; for (int i = 2; i < n; i++) { s[i] = 1; F[i] = (F[i - 1] + F[i - 2]) % mod; invF[i] = inv(F[i]); if(!isp[i]) plist[ptot++] = i, miu[i] = -1; for (int j = 0; j < ptot && i * plist[j] < n; j++) { int tmp = i * plist[j]; isp[tmp] = true; if (i % plist[j] == 0) { miu[tmp] = 0; break; } miu[tmp] = -miu[i]; } } for (int i = 1; i < n; i++) { for (int j = 1, k = i; k < n; j++, k += i) { if (miu[j] == 1) s[k] = 1ll * s[k] * F[i] % mod; if (miu[j] == -1) s[k] = 1ll * s[k] * invF[i] % mod; } } for (int i = 1; i < n; i++) { s[i] = 1ll * s[i] * s[i - 1] % mod; invs[i] = inv(s[i]); } } inline int min(int a, int b) {return a < b ? a : b;} int solve(int n, int m) { int tmp = min(n, m), ans = 1, j; for (int i = 1; i <= tmp; i = j + 1) { j = min(n / (n / i), m / (m / i)); ans = 1ll * ans * pw(1ll * s[j] * invs[i - 1] % mod, 1ll * (n / i) * (m / i) % (mod - 1)) % mod; } return ans; } int Tim, n, m; int main() { sieve(maxn); scanf("%d", &Tim); while (Tim --> 0) { scanf("%d%d", &n, &m); printf("%d\n", solve(n, m)); } return 0; }