V.[51Nod1355]斐波那契的最小公倍数
引理1. 设 (f_i) 表示斐波那契数列中第 (i) 项,则 (gcd(f_i,f_j)=f_{gcd(i,j)})。
一种证明方法是打表
另一种证明方法是,首先有 (f_{i+j}=f_{i−1}f_j+f_if_{j+1})(这个可以通过暴力拆斐波那契数得到)。显然,(f_{i-1}) 与 (f_i) 的 (gcd) 为 (1),(f_{j+1}) 与 (f_j) 的 (gcd) 为 (1)(这个是真的简单归纳就能得出),故 (gcd(f_{i+j},f_j)=gcd(f_i,f_j))。发现这就是求 (gcd) 的辗转相减法的形式,因此证毕。
引理2. (operatorname{lcm}{mathbb S}=prodlimits_{mathbb{Tsubseteq S}}gcd{mathbb T}^{(-1)^{|mathbb T|+1}})。
考虑对每一个质数进行minmax容斥。在枚举一个质数后,考虑 ( ext{lcm}) 中该质数的次数,为 (maxlimits_{xinmathbb S}{d_x}),其中 (d_x) 为 (x) 中此质数的次数。
于是 (maxlimits_{xinmathbb S}{d_x}=sumlimits_{mathbb{Tsubseteq S}}(-1)^{|T|+1}minlimits_{xinmathbb T}{d_x})。在将其移回指数上后,便得到了上述结论。
结合引理1,2,我们得到
现在考虑对于每个 (gcd),有多少符合条件的 (mathbb T),以及有多少个 (|mathbb T|) 为奇,多少个为偶。
考虑我们现在强行构造出一个数列 (g) 满足 (f_nequivprodlimits_{d|n}g_dpmod{10^9+7})。于是就有
现在考虑把 (g_d) 的指数掏出来,是 (sumlimits_{mathbb{Tsubseteq S},d|gcd{mathbb T}}(-1)^{|mathbb T|+1})。
考虑 (mathbb S) 中所有是 (d) 的倍数的数的数量,设其为 (p)。则上式等价于 (sumlimits_{k=1}^pdbinom{p}{k}(-1)^{k+1})。显然,当 (p) 为 (0) 时,此式为 (0);否则,其可被改写成 (1+sumlimits_{k=0}^pdbinom{p}{k}(-1)^{k+1})。依据二项式定理,后面那一大坨,在 (p>0) 时为 (0)。故其就等价于 ([p>0]),也即存在 (d) 的倍数。
于是问题转换为 (prodlimits_{exists xinmathbb S,d|x}g_d)。显然就可以简单求出。问题转换为如何构造 (g)。
因为 (f_n=prodlimits_{d|n}g_d),或许会想到狄利克雷卷积。但是狄利克雷卷积中是 (sum) 而非 (prod),因此不能使用。更好的方式是把除了 (g_n) 以外所有项全部移到另一边,得到 (g_n=dfrac{f_n}{prodlimits_{d|n,d eq n}g_d}),可以 (O(nsqrt{n})) 或 (O(nlog n)) 地递推。
总时间复杂度可以做到 (O(nlog n))。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int ksm(int x,int y=mod-2){int z=1;for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)z=1ll*z*x%mod;return z;}
int n,m,a[50100],g[1001000],res=1;
bool occ[1001000];
int main(){
scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),m=max(m,a[i]),occ[a[i]]=true;
g[0]=0,g[1]=1;for(int i=2;i<=m;i++)g[i]=(g[i-1]+g[i-2])%mod;
for(int i=1;i<=m;i++){
int inv=ksm(g[i]);
for(int j=2*i;j<=m;j+=i)g[j]=1ll*g[j]*inv%mod;
for(int j=i;j<=m;j+=i)if(occ[j]){res=1ll*res*g[i]%mod;break;}
}
printf("%d
",res);
return 0;
}