51nod 1355 斐波那契的最小公倍数 莫比乌斯反演+数学

题意

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=fnfm1+fn+1fm 来推导。

还有一个结论就是

lcm{S}=TS,Tϕgcd(T)(1)|T|+1

证明的话可以考虑知道每个子集的最小值通过容斥来求全集的最大值。
Max(S)=TS,Tϕ(1)|T|+1Min(T)
为什么这样是对的呢?如果真的无法把这个东西看做容斥的话可以这样想:
我们把全集从大到小排序后,第n个数出现的次数就是 i=0n1(1)iCin1
注意到这条式子只有当n=0时为1否则为0,因此得出来的是最大值。

从而可以得到

lcm(fS)=TS,Tϕgcd(fT)(1)|T|+1

=TS,Tϕ(fgcd(T))(1)|T|+1

然后我们构造数列 {gd} 满足 fn=d|ngd
那么有
lcm(fS)=TS,Tϕ(d|gcd(T)gd)(1)|T|+1

=d(gd)TS,Tϕ,d|gcd(T)(1)|T|+1

注意到其指数上的式子
TS,Tϕ,d|gcd(T)(1)|T|+1

当存在 xS 满足 d|x 时该式子为1,否则为0。
那么有
lcm(fS)=xS,d|xgd

在求出 gd 后这条式子显然可以在 O(nlogn) 内计算完毕。
gd 的话可以通过对定义式进行变形得到
gn=fn(d|n,dngd)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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值