[题解]斐波那契的最小公倍数
\[\color{red}{\textsf{小游者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?}} \\
\begin{array}{|}
\hline
\color{pink}{\text{A small swimmer is a God.}} \\
\color{pink}{\text{The left toilet and the right eternal God}} \\
\color{pink}{\text{can break the evil energy with a sharp pen.}} \\
\color{pink}{\text{Who can resist him? }} \\
\hline
\end{array} \\
\begin{array}{|}
\hline
\color{green}{\text{小遊者は、神であり、左便器、右永神であり}} \\
\color{green}{\text{鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? }} \\
\hline
\end{array} \\
\begin{array}{|}
\hline
\color{lightblue}{\text{Petit voyageur, est Dieu aussi, toilettes gauche, Dieu éternel droit,}} \\
\color{lightblue}{\text{peut tenir un stylo tranchant pour briser le mal, qui devrait le faire?}} \\
\hline
\end{array} \\
\begin{array}{|}
\hline
\color{purple}{\text{Der Direktor ist wirklich ein Gott}} \\
\color{purple}{\text{mit einer Toilette links und Yongshen rechts}} \\
\color{purple}{\text{der einen spitzen Stift hält}} \\
\color{purple}{\text{um die Wahrheit zu durchdringen.}} \\
\color{purple}{\text{Wer kann ihm widerstehen? }} \\
\hline
\end{array} \\
\begin{array}{|}
\hline
\color{cyan}{\text{Ein kleiner Schwimmer ist ein Gott.}} \\
\color{cyan}{\text{Die linke Toilette und der rechte ewige Gott können }} \\
\color{cyan}{\text{die böse Energie mit einem scharfen Stift brechen.}} \\
\color{cyan}{\text{Wer sollte es sein?}} \\
\hline
\end{array} \\
\color{red}{\textsf{对曰:“无人,狗欲当之,还请赐教!”}} \\
\newcommand\brak[1]{\left({#1}\right)}
\newcommand\Brak[1]{\left\{{#1}\right\}}
\newcommand\d[0]{\text{d}}
\newcommand\string[2]{\genfrac{\{}{\}}{0pt}{}{#1}{#2}}
\newcommand\down[2]{{#1}^{\underline{#2}}}
\newcommand\ddiv[2]{\left\lfloor\frac{#1}{#2}\right\rfloor}
\newcommand\udiv[2]{\left\lceil\frac{#1}{#2}\right\rceil}
\newcommand\lcm[0]{\operatorname{lcm}}
\newcommand\set[1]{\left\{{#1}\right\}}
\newcommand\ceil[1]{\left\lceil{#1}\right\rceil}
\newcommand\floor[1]{\left\lfloor{#1}\right\rfloor}
\newcommand\rhs[1]{\;\text{Rhs}\;#1}
\newcommand\lhs[1]{\;\text{Lhs}\;#1}
\newcommand\Vec[1]{\vec{\mathbf{#1}}}
\newcommand\rank[0]{\text{rank}}
\newcommand\group[1]{\left\langle\right\rangle}
\newcommand\norm[1]{\left|{#1}\right|}
\]
题解
直接算每个质数的指数,对于每个质数 \(p_i\),设 \(F(p,a_i)\) 表示斐波那契数列的 \(F(a_i)\) 含有 \(p\) 多少。
\[\max\set{F(p,a_i)}=\sum_{T\subset U}(-1)^{\norm T+1}\min\set{F(p,a_j)|a_j\in T}
\]
发现是 \(\lcm\) 向 \(\gcd\) 的容斥:
\[\begin{aligned}
\lcm{F(a_i)}&=\prod_{T\subset U}\gcd(F(a_i))^{(-1)^{\norm T+1}} \\
&=\prod_{T\subset U}F(\gcd(a_i))^{(-1)^{\norm T+1}}
\end{aligned}
\]
设在 \(\set {a_i}\) 中选择 \(k\) 个数,他们的 \(\gcd\) 是 \(d\) 的方案数为 \(g(k,d)\),是 \(d\) 的倍数的方案数为 \(f(k,d)\),那么显然有
\[f(k,n)=\sum_{d\mid n}g(k,d)\Rightarrow g(k,n)=\sum_{n\mid d}\mu\brak{d\over n}f(k,d)
\]
而我们要求的是
\[\lcm=\prod_{i=1}^\infty F(i)^{\sum_{j=1}^n (-1)^{j+1}\times g(j,i)}
\]
专注于指数的运算:
\[\sum_{j=1}^n(-1)^{j+1}g(j,i)=\sum_{j=1}^n(-1)^{j+1}\sum_{i\mid d} \mu\brak{d\over i}f(j,d)=\sum_{i\mid d}\mu\brak{d\over i}\sum_{j=1}^n(-1)^{j+1}f(j,d)
\]
设 \(\set {a_i}\) 中 \(d\) 的倍数有 \(cnt(d)\) 个,那么 \(\displaystyle f(j,d)={cnt(d)\choose j}\),继续
\[(*)=\sum_{i\mid d}\mu\brak{d\over i}\sum_{j=1}^n(-1)^{j+1}{cnt(d)\choose j}
\]
显然 \(cnt(d)\le n\),因此可以将后面的东西改一下
\[(*)=\sum_{i\mid d}\mu\brak{d\over i}\sum_{j=1}^{cnt(d)}(-1)^{j+1}{cnt(d)\choose j}
\]
注意到 \(\displaystyle \sum_{j=0}^{cnt(d)}(-1)^{j+1}{cnt(d)\choose d}=-1\times \sum_{j=0}^{cnt(d)}(-1)^j{cnt(d)\choose j}=-(1-1)^{cnt(d)}=0\),因此 \(\displaystyle \sum_{j=1}^{cnt(j)}(-1)^{j+1}{cnt(d)\choose j}=[cnt(j)>0]\),所以
\[(*)=\sum_{i\mid d}\mu\brak{d\over i}[cnt(d)>0]
\]
对于每一个 \(F(i)\),都计算一下它头顶上的系数,直接暴力枚举 \(d\) 就行了,因为这是 \(\mathcal O(A\ln A)\) 的,其中 \(A=\max a_i\).
参考代码
/** @author __Elaina__ */
// #pragma GCC optimize("Ofast")
// #pragma GCC optimize("inline")
// #define GCC optimize(2)
// #define GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
// #define USING_FREAD
// #define NDEBUG
#include <cassert>
namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */
#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;
template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }
#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI ((char)getchar())
#endif
template<class T> inline T readret(T x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
return f ? -x : x;
}
template<class T> inline void readin(T& x) {
x = 0; int f = 0; char c;
while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
if (x < 0) putchar('-'), x = -x;
static int __stk[55], __bit = 0;
do __stk[++__bit] = x % 10, x /= 10; while (x);
while (__bit) putchar(__stk[__bit--] ^ 48);
putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
return min(x, listMin(args...));
}
} // namespace Elaina
using namespace Elaina;
const int Maxn = 1e6;
const int mod = 1e9 + 7;
inline int qkpow(int a, int n) {
int ret = 1;
for (; n > 0; n >>= 1, a = (int)(1ll * a * a % mod))
if (n & 1) ret = (int)(1ll * ret * a % mod);
return ret;
}
int a[Maxn + 5], n;
int cnt[Maxn + 5], buc[Maxn + 5];
bool vis[Maxn + 5];
int prime[Maxn + 5], mu[Maxn + 5];
inline void sieve() {
vis[1] = true, mu[1] = 1;
rep (i, 2, Maxn) {
if (!vis[i]) prime[++*prime] = i, mu[i] = -1;
for (int j = 1; j <= *prime && i * prime[j] <= Maxn; ++j) {
vis[i * prime[j]] = true;
if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; }
mu[i * prime[j]] = -mu[i];
}
}
}
signed main() {
readin(n);
rep (i, 1, n) ++buc[readret(1)];
rep (i, 1, Maxn)
for (int j = i; j <= Maxn; j += i)
cnt[i] += buc[j];
sieve();
int fl = 0, fc = 1, ans = 1, tmp;
rep (i, 1, Maxn) {
int p = 0;
for (int d = i; d <= Maxn; d += i) if (cnt[d] > 0) p += mu[d / i];
if (p < 0) tmp = qkpow(fc, mod - 2), p = -p;
else tmp = fc;
ans = (int)(1ll * ans * qkpow(tmp, p) % mod);
tmp = (fl + fc) % mod, fl = fc, fc = tmp;
}
writln(ans);
return 0;
}