2693: jzptab/2154: Crash的数字表格 莫比乌斯反演

本文详细解析了一个涉及数学算法的问题,通过引入莫比乌斯函数和线性筛法等高级概念,将原始问题转换为易于计算的形式,并最终实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

神题……不会做啊……抄题解吧……

以下题解来自网上(某爬虫网站的我也不知道原作者是谁)


下边均设n<=m

i=1nj=1mlcm(i,j)=i=1nj=1mij(i,j)

然后我们要想枚举d=(i,j),那么就要确定ij怎么取,显然我们只需要先除去ijd,也就是(i/d,j/d)=1就行了,那么设

F(x,y)=i=1xj=1yij[(i,j)=1]

那么原式变成

d=1nd2F(nd,md)d=d=1ndF(nd,md)

考虑求F(x,y)

F(x,y)=i=1xj=1yij[(i,j)=1]=i=1xj=1yijd|(i,j)μ(d)=d=1xμ(d)d|ixid|jyj=d=1xμ(d)d2i=1xdj=1yd1=d=1xμ(d)d2xd(xd+1)2yd(yd+1)2

带回原式得

==d=1ndF(nd,md)d=1ndi=1ndμ(i)i2ndi(ndi+1)2mdi(mdi+1)2d=1ndi=1ndμ(i)i2ndi(ndi+1)2mdi(mdi+1)2

现在已经可以O(nn)=O(n)单次查询了,但是不够理想,我们继续化简

T=di,则i|T,d=T/i,换掉指标,得

==d=1ndi=1ndμ(i)i2ndi(ndi+1)2mdi(mdi+1)2T=1nnT(nT+1)2mT(mT+1)2i|TTiμ(i)i2T=1nnT(nT+1)2mT(mT+1)2Ti|Tμ(i)i

g(T)=Ti|Tμ(i)i,我们再设f(T)=i|Tμ(i)i那么g(T)=Tf(T),考虑求f(T)

在线性筛中,外层为k,内层为py,所以求f(kpy)=i|Tμ(i)i
py|k
i取的数的因子中不包含新加入的py时,答案就是f(k)
i取包含新加入的因子py时,由于此时py指数已经>=2,所以μ(i)=0,因此贡献为0
综上,当py|k时,答案为f(k)

pyk
i取的数的因子中不包含新加入的py时,同上,答案是f(k)
i取的数的因子包含新加入的py时,由于指数为1,所以我们考虑i=apy,原式变为

====i|Tμ(i)iapy|kpyμ(apy)apypya|kμ(a)μ(py)apya|kμ(a)apyf(k)

综上,当pyk时,答案为(1py)f(k)

然后线性筛随便搞搞即可,最后答案就是

T=1nnT(nT+1)2mT(mT+1)2g(T)

F(x,y)=i=1xj=1yij[(i,j)=1]=i=1xj=1yijd|(i,j)μ(d)

感觉这一步转化好神啊,完全想不到。
#include<iostream>
#include<cstdio>
#define ll long long 
#define M 100000009
#define N 10000005
using namespace std;
int prime[N],mobius[N];
bool flag[N];
ll f[N];
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline void prepare()
{
    mobius[1]=1; f[1]=1;
    for (int i=2;i<N;i++)
    {
        if (!flag[i]) prime[++prime[0]]=i,mobius[i]=-1,f[i]=1-i;
        for (int j=1;j<=prime[0]&&i*prime[j]<N;j++)
        {
            flag[i*prime[j]]=1;
            if (i%prime[j]==0) {mobius[i*prime[j]]=0; f[i*prime[j]]=f[i]; break;}
            mobius[i*prime[j]]=-mobius[i]; f[i*prime[j]]=(f[i]*f[prime[j]])%M;
        }
    }
    for (int i=1;i<N;i++)
        f[i]=(f[i-1]+f[i]*i%M)%M;
}   
inline ll sum(ll n,ll m)
{
    return (n*(n+1)/2%M)*(m*(m+1)/2%M)%M;
}
inline ll work(ll n,ll m)
{
    ll ans=0;
    for (ll i=1,pos;i<=n;i=pos+1)
    {
        pos=min(n/(n/i),m/(m/i));
        ans=(ans+(f[pos]-f[i-1]+M)%M*sum(n/i,m/i)%M)%M;
    }
    return ans;
}
int main()
{
    int testcase=read();
    prepare();
    while (testcase--)
    {
        ll n=read(),m=read();
        if (n>m) swap(n,m);
        printf("%lld\n",(work(n,m)+M)%M);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值