牛客练习赛#84 F 莫比乌斯反演+杜教筛+技巧+斐波那契数列和gcd的结论+矩阵快速幂

本文探讨了一种利用斐波那契数列和莫比乌斯函数求解高维 gcd 的巧妙方法,通过递归和莫比乌斯反演技巧,简化了复杂计算。关键结论包括 gcd 的性质和斐波那契数列项的求和公式。

题意:

给出n,kn,kn,k,计算
∑i1=1n∑i2=1n...∑in=1ngcd(fi1,fi2,...,fin) \sum_{i_{1}=1}^{n}\sum_{i_{2}=1}^{n}...\sum_{i_{n}=1}^{n}gcd(f_{i_{1}},f_{i_{2}},...,f_{i_{n}}) i1=1ni2=1n...in=1ngcd(fi1,fi2,...,fin)

Solution:

这题结论有点多,先给出来,后附第二条的证明,第一条难度太大

结论111

gcd(fi1,fi2,....,fin)=fgcd(i1,i2,...,in) gcd(f_{i_{1}},f_{i_{2}},....,f_{i_{n}})=f_{gcd(i_{1},i_{2},...,i_{n})} gcd(fi1,fi2,....,fin)=fgcd(i1,i2,...,in)

于是即计算
∑i1=1n∑i2=1n...∑in=1nfgcd(i1,i2,...,in) \sum_{i_{1}=1}^{n}\sum_{i_{2}=1}^{n}...\sum_{i_{n}=1}^{n}f_{gcd(i_{1},i_{2},...,i_{n})} i1=1ni2=1n...in=1nfgcd(i1,i2,...,in)
显然枚举因子,这里因子为gcdgcdgcd项,即
∑d=1nfd∑i1=1n∑i2=1n...∑in=1n[gcd(i1,i2,...,in)=d] \sum_{d=1}^{n}f_{d}\sum_{i_{1}=1}^{n}\sum_{i_{2}=1}^{n}...\sum_{i_{n}=1}^{n}[gcd(i_{1},i_{2},...,i_{n})=d] d=1nfdi1=1ni2=1n...in=1n[gcd(i1,i2,...,in)=d]
这是个莫比乌斯反演的经典形式了
∑d=1nfd∑i1=1⌊nd⌋∑i2=1⌊nd⌋...∑in=1⌊nd⌋[gcd(i1,i2,...,in)=1]=∑d=1nfd∑i1=1⌊nd⌋∑i2=1⌊nd⌋...∑in=1⌊nd⌋∑t∣gcd(i1,i2,...,in)μ(t) \sum_{d=1}^{n}f_{d}\sum_{i_{1}=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{i_{2}=1}^{\lfloor \frac{n}{d} \rfloor}...\sum_{i_{n}=1}^{\lfloor \frac{n}{d} \rfloor}[gcd(i_{1},i_{2},...,i_{n})=1]=\sum_{d=1}^{n}f_{d}\sum_{i_{1}=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{i_{2}=1}^{\lfloor \frac{n}{d} \rfloor}...\sum_{i_{n}=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{t|gcd(i_{1},i_{2},...,i_{n})}\mu(t) d=1nfdi1=1dni2=1dn...in=1dn[gcd(i1,i2,...,in)=1]=d=1nfdi1=1dni2=1dn...in=1dntgcd(i1,i2,...,in)μ(t)
再次优先枚举因子,这里为ttt
∑d=1nfd∑t=1⌊nd⌋μ(t)⌊ndt⌋k \sum_{d=1}^{n}f_{d}\sum_{t=1}^{\lfloor \frac{n}{d} \rfloor}\mu(t)\lfloor \frac{n}{dt} \rfloor^{k} d=1nfdt=1dnμ(t)dtnk

到这里,我的思路为枚举T=dtT=dtT=dt,即计算
∑T=1n⌊nT⌋k∑d∣Tμ(d)f(Td) \sum_{T=1}^{n}\lfloor \frac{n}{T} \rfloor^{k}\sum_{d|T}\mu(d)f(\frac{T}{d}) T=1nTnkdTμ(d)f(dT)
第二个求和形式极其像莫比乌斯反演的变换形式,但很可惜,斐波那契数列不是一个积性函数,否则将是绝杀,只能作罢

不能化简的话,有一个技巧,第二个求和发现上界是一个下取整,把他令成一个函数
R(x)=∑i=1xμ(i)⌊xi⌋ R(x)=\sum_{i=1}^{x}\mu(i)\lfloor \frac{x}{i} \rfloor R(x)=i=1xμ(i)ix
先把他代入原式我们再分析他的妙处,原式即
∑d=1nfdR(⌊nd⌋) \sum_{d=1}^{n}f_{d}R(\lfloor \frac{n}{d} \rfloor) d=1nfdR(dn)
首先,这个表达式有下取整,可以数论分块;其次,R(x)R(x)R(x)内部也有下取整,又可以数论分块,并且求R(x)R(x)R(x)需要μ\muμ的前缀和,这恰好就是杜教筛!

解决了R(x)R(x)R(x)部分,那么求上式也需要fff的前缀和,如何处理?

结论222

∑i=1nfi=fn+2−1 \sum_{i=1}^{n}f_{i}=f_{n+2}-1 i=1nfi=fn+21

那么只需要求斐波那契的一个项即可,矩阵快速幂即可轻松做到

结论222证明:

利用累加法,设S(n)S(n)S(n)为斐波那契数列的前nnn项和:
f3=f2+f1f4=f3+f2...fn=fn−1+fn−2 f_{3}=f_{2}+f_{1}\\ f_{4}=f_{3}+f_{2}\\ ...\\ f_{n}=f_{n-1}+f_{n-2}\\ f3=f2+f1f4=f3+f2...fn=fn1+fn2
对应位置全部相加,得到:
S(n)−f1−f2=(S(n)−f1−fn)+(S(n)−fn−1−fn) S(n)-f_{1}-f_{2}=(S(n)-f_{1}-f_{n})+(S(n)-f_{n-1}-f_{n}) S(n)f1f2=(S(n)f1fn)+(S(n)fn1fn)
f1=f2=1f_{1}=f_{2}=1f1=f2=1,合并得到
S(n)=2fn+fn−1−1 S(n)=2f_{n}+f_{n-1}-1 S(n)=2fn+fn11
递推公式合并右式,就得到了
S(n)=fn+2−1 S(n)=f_{n+2}-1 S(n)=fn+21
同理是可以得到奇数项和,偶数项和的

// #include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<bitset>
#include<map>
using namespace std;

using ll=long long;
const int N=2e5+5,inf=0x3fffffff;
const long long INF=0x3fffffffffffffff,mod=1e9+9;

ll qm(ll x){return (x%mod+mod)%mod;}

struct matrix
{
    ll a[2][2];
    void initial(){memset(a,0,sizeof(a));}
    void build()
    {
        initial();
        for(int i=0;i<2;i++) a[i][i]=1;
    }
    ll* operator[](int i) const {
        return (ll*)&a[i][0];
    }
    matrix operator*(const matrix& x) const
    {
        matrix ret; ret.initial();
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                for(int k=0;k<2;k++) ret[i][j]=(ret[i][j]+a[i][k]*x[k][j]%mod)%mod;
        return ret;
    }
}ans={{
    {1,1},
    {0,0}
}},tmp={{
    {1,1},
    {1,0}
}};

matrix qpow(matrix a,ll b)
{
    matrix ret,base=a; ret.build();
    while(b)
    {
        if(b&1) ret=ret*base;
        base=base*base;
        b>>=1;
    }
    return ret;
}

ll f(int x)
{
    if(x<=2)
    {
        if(x==0) return 0;
        return 1;
    }
    return qm((ans*qpow(tmp,x-2))[0][0]);
}

ll fpre(int x){return qm(f(x+2)-1);}

ll qpow(ll a,ll b)
{
    ll ret=1,base=a;
    while(b)
    {
        if(b&1) ret=ret*base%mod;
        base=base*base%mod;
        b>>=1;
    }
    return ret;
}

int mu[N],cnt,prime[N];
bool nt[N];
map<int,ll>map1;

void make_prime()
{
    mu[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!nt[i]) prime[++cnt]=i,mu[i]=mod-1;
        for(int j=1;j<=cnt&&i*prime[j]<N;j++)
        {
            nt[i*prime[j]]=true;
            if(i%prime[j]==0) break;
            else mu[i*prime[j]]=qm(1ll*mu[i]*mu[prime[j]]);
        }
    }
    for(int i=1;i<N;i++) mu[i]=qm(1ll*mu[i]+1ll*mu[i-1]);
}

ll calcmu(int x)
{
    if(x<N) return 1ll*mu[x];
    if(map1.count(x)) return map1[x];
    ll ret=1;
    for(int l=2,r;l<=x;l=r+1)
    {   
        r=x/(x/l);
        ret=qm(ret-(r-l+1)*calcmu(x/l));
    }
    return map1[x]=ret;
}

int n,k;

ll R(int x)
{
    ll ret=0;
    for(int l=1,r;l<=x;l=r+1)
    {
        r=x/(x/l);
        ret=qm(ret+qm(calcmu(r)-calcmu(l-1))*qpow(x/l,k));
    }
    return ret;
}

int main()
{
    make_prime();
    cin>>n>>k; ll res=0;
    for(int l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        res=qm(res+qm(fpre(r)-fpre(l-1))*R(n/l));
    }
    cout<<res;
    return 0;  
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值