「51nod1190」最小公倍数之和 V2 题解

本文网址:https://www.cnblogs.com/zsc985246/p/17389399.html ,转载请注明出处。

前置知识

2023/5/18update:更正了第 8 个公式。

莫比乌斯函数定义:

对于一个数 n=p1q1p2q2pkqk,其中 p 为素数,那么

μ(n)={1,n=1(1)k,ki=1qi=10,otherwise

莫比乌斯反演的一种形式:[x=1]=d|xμ(d)

积性函数:对于任意互质的正整数 abf(ab)=f(a)f(b)数论函数

数论函数:定义域为正整数,陪域为复数的函数。

题目大意

给定 a,b,求 bi=alcm(i,b)mod109+7

1ab109

思路

看到 lcm 想到 gcd

i=ablcm(i,b)=i=abibgcd(i,b)                       =bi=abigcd(i,b)

然后对于分数,一个常用的套路就是枚举因数。

=bx|bi=abix[gcd(i,b)=x]   =bx|bi=abix[gcd(ix,bx)=1] =bx|bi=axbxi[gcd(i,bx)=1]

然后我们根据莫比乌斯反演,直接将 [gcd(i,bx)=1] 换掉。

=bx|bi=axbxiy|gcd(i,bx)μ(y)                  =bx|by|bxμ(y)i=axbxi[imody=0]=bx|by|bxμ(y)i=axybxyyi     

然后发现最后面的那一坨其实就是等差数列求和,直接拆开就好。

=bx|by|bxμ(y)y(bxy+axy)(bxyaxy+1)2    =b2x|by|bxμ(y)y(bxy+axy)(bxyaxy+1)

我们调换一下枚举的顺序,先枚举一个 y=xy,然后再枚举 x|y

=b2y|b(by+ay)(byay+1)x|yμ(x)x

找出 b 的因数就可以解决前面的式子,所以现在我们只需要处理 x|yμ(x)x

由于 b 的范围是 109,我们不能直接预处理 μ(x),所以需要另寻方法。

我们令 f(x)=d|xμ(d)d

f(a)f(b)=x|aμ(x)x×y|bμ(y)y         =x|ay|bμ(x)μ(y)xy=d|abμ(d)d      =f(ab)             

所以 f(x) 是积性函数。

而我们又知道对一个质数 p 和任意正整数 kf(pk)=μ(1)+μ(p)p+ki=2μ(pi)pi=1p

所以如果 n=p1q1p2q2pkqk,其中 p 为素数,那么 f(n)=ki=11pk

那么我们就可以在枚举因数 d 时直接计算 f(d) 的值了。

代码实现

多测不清空,爆零两行泪。

#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
const ll N=1e6+10;
using namespace std;
const ll mod=1e9+7;

ll vis[N],tot,p[N];
void init(ll n){//质数筛
    For(i,2,n){
        if(!vis[i])p[++tot]=i;
        For(j,1,tot){
            if(i*p[j]>n)break;
            vis[i*p[j]]=1;
            if(i%p[j]==0)break;
        }
    }
}

ll cnt,t[N],num[N];//t为质因数,num为出现的个数
void solve(ll x){//质因数分解
    for(ll i=1;p[i]*p[i]<=x;i++){
        if(x%p[i]==0){
            t[++cnt]=p[i];
            num[cnt]=0;
            while(x%p[i]==0)num[cnt]++,x/=p[i];
        }
    }
    if(x>1)t[++cnt]=x,num[cnt]=1;
}

ll a,b,ans;
void dfs(ll x,ll d,ll s){//第x个质因数,目前枚举的因数为d,f(d)=s
    if(x>cnt){//按公式计算答案
        ll t1=b/d,t2=(a+d-1)/d;
        ans=(ans+(t1+t2)*(t1-t2+1)*s%mod+mod)%mod;
        return;
    }
    dfs(x+1,d,s);//不选当前质因数
    s=s*(1-t[x]);//积性函数直接计算
    For(i,1,num[x]){//选i个当前质因数
        d*=t[x];
        dfs(x+1,d,s);
    }
}

void mian(){

    scanf("%lld%lld",&a,&b);
    cnt=ans=0;//记得清空
    solve(b);
    dfs(1,1,1);
    printf("%lld\n",ans*500000004%mod*b%mod);//500000004是2在模1000000007下的逆元

}

int main(){
    init(50000);
    int T=1;
    scanf("%d",&T);
    while(T--)mian();
    return 0;
}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

posted @   zsc985246  阅读(238)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示