斐波那契的最小公倍數 題解
題目大意
給出 \(n\) 以及一個長度為 \(n\) 的陣列 \(a_{1,2,...,n}\) ,定義 \(f_i\) 表示斐波拉契數列的第 \(i\) 項,其中 \(f_1=f_2=1\) 。求出 \(\text{lcm}\{f_{a_1},f_{a_2},...,f_{a_n}\}\) 。
\(n\le 5\times 10^4,a_i\le 10^6\)
思路
算是讓我見識了 \(\text{min-max}\) 容斥有多強。做這道題首先你得知道一個知道一個式子:
\[\text{lcm}\{S\}=\prod_{T\subseteq S}\gcd\{T\}^{(-1)^{|T|+1}} \]
具體證明可以考慮我們對於質因數分解的每一位做 \(\text{min-max}\) 容斥。
然後看到這道題,我們又有一個人盡皆知的定理 \(\gcd(f_i,f_j)=f_{\gcd(i,j)}\),然後就可得到:
\[\text{lcm}\{S\}=\prod_{T\subseteq S}f_{\gcd\{T\}}^{(-1)^{|T|+1}} \]
\[=\prod_{i=1}^{\infty} f_i^{\sum_{T\subseteq S} [\gcd\{T\}=i](-1)^{|T|+1}} \]
然後上面那一坨不是很好求,所以我們可以考慮莫比烏斯反演解決,我們設 \(a_i=\sum_{T\subseteq S} [\gcd\{T\}=i](-1)^{|T|+1}\)
\[b_i=\sum_{T\subseteq S}[i|\gcd\{T\}](-1)^{|T|+1} \]
然後你發現如果 \(i\) 在 \(T\) 中出現過,那麼 \(b_i=1\),反之為 \(0\),具體證明可以使用二項式定理。
然後我們使用莫比烏斯反演可以得到:
\[a_i=\sum_{i|d}\mu(\frac{d}{i})b_d \]
然後直接預處理之後暴力算就好了,時間複雜度為 \(\Theta(w\ln w)\) ,其中 \(w\) 是值域。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 1000000007 #define MAX 1000000 int n,tot,f[MAX + 5],a[MAX + 5],b[MAX + 5],mu[MAX + 5],vis[MAX + 5],prime[MAX + 5]; void Euler (int up){ mu[1] = 1; for (Int i = 2;i <= up;++ i){ if (!vis[i]) prime[++ tot] = i,mu[i] = -1; for (Int j = 1;j <= tot && i * prime[j] <= up;++ j){ vis[i * prime[j]] = 1; if (i % prime[j] == 0) break; else mu[i * prime[j]] = -mu[i]; } } } int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod; return res; } template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} signed main(){ read (n),Euler (MAX); for (Int i = 1,x;i <= n;++ i) read (x),b[x] = 1; for (Int i = 1;i <= MAX;++ i) for (Int j = i + i;j <= MAX;j += i) b[i] |= b[j]; f[1] = f[2] = 1;for (Int i = 2;i <= MAX;++ i) f[i] = (f[i - 1] + f[i - 2]) % mod; for (Int i = 1;i <= MAX;++ i) for (Int j = i;j <= MAX;j += i) a[i] += mu[j / i] * b[j]; int ans = 1;for (Int i = 1;i <= MAX;++ i) ans = 1ll * ans * qkpow (f[i],mod - 1 + a[i]) % mod; write (ans),putchar ('\n'); return 0; }