题意
F(0) = 0 F(1) = 1
F(n) = F(n-1) + F(n-2)
给出n个正整数a1, a2,…… an,求对应的斐波那契数的最小公倍数,由于数字很大,输出Mod 1000000007的结果即可。
2 <= N <= 50000,1 <= ai <= 1000000。
分析
跪zyz大爷写的题解。
首先有个结论就是
gcd(fn,fm)=fgcd(n,m)
证明的话可以根据 fn+m=fn∗fm−1+fn+1∗fm 来推导。
还有一个结论就是
lcm{S}=∏T⊆S,T≠ϕgcd(T)(−1)|T|+1
证明的话可以考虑知道每个子集的最小值通过容斥来求全集的最大值。
Max(S)=∑T⊆S,T≠ϕ(−1)|T|+1∗Min(T)
为什么这样是对的呢?如果真的无法把这个东西看做容斥的话可以这样想:
我们把全集从大到小排序后,第n个数出现的次数就是 ∑i=0n−1(−1)i∗Cin−1
注意到这条式子只有当n=0时为1否则为0,因此得出来的是最大值。
从而可以得到
lcm(fS)=∏T⊆S,T≠ϕgcd(fT)(−1)|T|+1
=∏T⊆S,T≠ϕ(fgcd(T))(−1)|T|+1
然后我们构造数列 {gd} 满足 fn=∏d|ngd
那么有
lcm(fS)=∏T⊆S,T≠ϕ(∏d|gcd(T)gd)(−1)|T|+1
=∏d(gd)∑T⊆S,T≠ϕ,d|gcd(T)(−1)|T|+1
注意到其指数上的式子
∑T⊆S,T≠ϕ,d|gcd(T)(−1)|T|+1
当存在 x∈S 满足 d|x 时该式子为1,否则为0。
那么有
lcm(fS)=∏∃x∈S,d|xgd
在求出 gd 后这条式子显然可以在 O(nlogn) 内计算完毕。
求 gd 的话可以通过对定义式进行变形得到
gn=fn∗(∏d|n,d≠ngd)−1
那么 gd 显然也可以在 O(nlogn) 内预处理完毕,问题解决。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=1000005;
const int MOD=1000000007;
int n,f[N];
bool vis[N];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
int main()
{
n=read();int mx=0;
for (int i=1;i<=n;i++)
{
int x=read();
mx=max(mx,x);vis[x]=1;
}
for (int i=1;i<=mx;i++)
for (int j=i;j<=mx;j+=i)
vis[i]|=vis[j];
f[1]=f[2]=1;
for (int i=3;i<=mx;i++) f[i]=f[i-1]+f[i-2],f[i]-=f[i]>=MOD?MOD:0;
int ans=1;
for (int i=1;i<=mx;i++)
{
int ny=ksm(f[i],MOD-2);
for (int j=i*2;j<=mx;j+=i) f[j]=(LL)f[j]*ny%MOD;
if (vis[i]) ans=(LL)ans*f[i]%MOD;
}
printf("%d",ans);
return 0;
}