【51nod1355】斐波那契的最小公倍数(min-max容斥)

【51nod1355】斐波那契的最小公倍数(min-max容斥)

题面

51nod

题解

显然直接算还是没法算的,所以继续考虑\(min-max\)容斥计算。
\[lcm(S)=\prod_{T\subset S}gcd(T)^{(-1)^{|T|+1}}\]
而斐波那契数列满足\(gcd(f(a),f(b))=f(gcd(a,b))\)
于是和最小公倍佩尔数一样的类似处理
\[lcm(S)=\prod_{i=1}^{\infty}f(i)^{\sum_{T\subset S}[gcd(T)=i](-1)^{|T|+1}}\]
\(a[i]\)是上面那一堆东西,\(b[i]=\sum_{i|d}a[i]\)
然后发现
\[b[i]=\prod_{T\subset S}[i|gcd(T)](-1)^{|T|+1}\]
只和是否存在\(i\)的倍数相关,存在就是\(1\),不存在就是\(0\)
那么预处理一下就可以算出\(b\)
而根据莫比乌斯反演,有
\[a[i]=\sum_{i|d}\mu(\frac{d}{i})b[d]\]
所以答案式就是:
\[\begin{aligned} lcm(S)&=\prod_{i=1}^{\infty}f(i)^{\sum_{T\subset S}[gcd(T)=i](-1)^{|T|+1}}\\ &=\prod_{i=1}^{\infty}f(i)^{\sum_{i|d}\mu(\frac{d}{i})b[d]} \end{aligned}\]
也可以预处理之后爆算了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 1001000
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int cnt[MAX];
bool zs[MAX];
int pri[MAX],tot,mu[MAX];
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
int n,ans=1,a[MAX],b[MAX],f[MAX];
void Sieve(int n)
{
    mu[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!zs[i])pri[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot&&i*pri[j]<=n;++j)
        {
            zs[i*pri[j]]=true;
            if(i%pri[j])mu[i*pri[j]]=-mu[i];
            else break;
        }
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)b[read()]=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;
    Sieve(MAX-1);
    for(int i=1;i<MAX;++i)
        for(int j=i;j<MAX;j+=i)
            a[i]+=mu[j/i]*b[j];
    for(int i=1;i<MAX;++i)
        if(a[i]>0)ans=1ll*ans*fpow(f[i],a[i])%MOD;
        else if(a[i]<0)ans=1ll*ans*fpow(f[i],MOD-1+a[i])%MOD;
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/10923779.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值