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

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

題面

51nodhtml

題解

顯然直接算仍是無法算的,因此繼續考慮\(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}\]
也能夠預處理以後爆算了。ios

#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;
}
相關文章
相關標籤/搜索