• 洛谷P2257 莫比乌斯反演+线性筛


    题意:

    给出 n , m n,m n,m,计算有多少 i ∈ [ 1 , n ] , j ∈ [ 1 , m ] i\in[1,n],j\in[1,m] i[1,n],j[1,m],使得 g c d ( i , j ) gcd(i,j) gcd(i,j)是一个素数

    Solution:

    不妨转化为枚举这个素数,找有多少对满足条件
    ∑ p ∈ p r i m e ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = p ] \sum_{p\in prime}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=p] pprimei=1nj=1m[gcd(i,j)=p]
    凑出莫比乌斯反演的形式,得到
    ∑ p ∈ p r i m e ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 ⌊ m p ⌋ ∑ d ∣ g c d ( i , j ) μ ( d ) \sum_{p\in prime}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{p}\rfloor}\sum_{d|gcd(i,j)}\mu(d) pprimei=1pnj=1pmdgcd(i,j)μ(d)
    优先枚举因子,并且设 n ≤ m n\leq m nm
    ∑ p ∈ p r i m e ∑ d = 1 ⌊ n p ⌋ μ ( d ) ⌊ n p d ⌋ ⌊ m p d ⌋ \sum_{p\in prime}\sum_{d=1}^{\lfloor\frac{n}{p}\rfloor}\mu(d)\lfloor\frac{n}{pd}\rfloor\lfloor\frac{m}{pd}\rfloor pprimed=1pnμ(d)pdnpdm
    优先枚举乘积,然后就可以将一部分转化为枚举因子,这里枚举 T = p d T=pd T=pd
    ∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ p ∈ p r i m e , p ∣ T μ ( T p ) \sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{p\in prime,p|T} \mu(\frac{T}{p}) T=1nTnTmpprime,pTμ(pT)
    前面的部分可以数论分块解决,现在只需要快速求得
    f ( T ) = ∑ p ∈ p r i m e , p ∣ T μ ( T p ) f(T)=\sum_{p\in prime,p|T} \mu(\frac{T}{p}) f(T)=pprime,pTμ(pT)
    可以线性筛筛出这个函数,线性筛关键在于添加一个质因子会带来什么后果,这里我们假设给 T T T加上一个质因子 p p p

    有关莫比乌斯函数,不妨先假设 T T T的唯一分解为:
    T = p 1 a 1 p 2 a 2 . . . p n a n T=p_{1}^{a_{1}}p_{2}^{a_{2}}...p_{n}^{a_{n}} T=p1a1p2a2...pnan

    • 如果 T T T包含了 p p p,那么 T p Tp Tp的唯一分解中 p p p的幂 ≥ 2 \geq2 2,而当 p ′ ≠ p p'\neq p p=p T p ′ \frac{T}{p'} pT必然包括平方因子 p 2 p^2 p2,此时所有的莫比乌斯函数值为 0 0 0,只有当 p ′ = p p'=p p=p时, T p ′ \frac{T}{p'} pT才有可能不出现平方因子,于是此时
      f ( T p ) = μ ( T ) f(Tp)=\mu(T) f(Tp)=μ(T)

    • 如果 T T T不包含 p p p,那么此时 T p Tp Tp的唯一分解为
      T p = p 1 a 1 p 2 a 2 . . . p n a n p Tp=p_{1}^{a_{1}}p_{2}^{a_{2}}...p_{n}^{a_{n}}p Tp=p1a1p2a2...pnanp

      枚举出所有的 T p ′ \frac{T}{p'} pT,有
      p 2 a 2 p 3 a 3 . . . p n a n p p 1 a 1 p 3 a 3 . . . p n a n p p 1 a 1 p 2 a 2 . . . p n a n p . . . p 1 a 1 p 2 a 2 . . . p n a n p_{2}^{a_{2}}p_{3}^{a_{3}}...p_{n}^{a_{n}}p\\ p_{1}^{a_{1}}p_{3}^{a_{3}}...p_{n}^{a_{n}}p\\ p_{1}^{a_{1}}p_{2}^{a_{2}}...p_{n}^{a_{n}}p\\ ...\\ p_{1}^{a_{1}}p_{2}^{a_{2}}...p_{n}^{a_{n}} p2a2p3a3...pnanpp1a1p3a3...pnanpp1a1p2a2...pnanp...p1a1p2a2...pnan
      除了最后一项都带有 p p p,而莫比乌斯函数是个积性函数,所以要求除了最后一项的莫比乌斯函数值,可以求得前面的部分,再乘 μ ( p ) \mu(p) μ(p),比如说第一项
      μ ( p 2 a 2 p 3 a 3 . . . p n a n p ) = μ ( p 2 a 2 p 3 a 3 . . . p n a n ) μ ( p ) \mu(p_{2}^{a_{2}}p_{3}^{a_{3}}...p_{n}^{a_{n}}p)=\mu(p_{2}^{a_{2}}p_{3}^{a_{3}}...p_{n}^{a_{n}})\mu(p) μ(p2a2p3a3...pnanp)=μ(p2a2p3a3...pnan)μ(p)
      此时我们将除最后一项的其他项都写成这样的形式,可以提出一个 μ ( p ) \mu(p) μ(p),此时这些的求和就为
      μ ( p ) [ μ ( p 2 a 2 p 3 a 3 . . . p n a n ) + μ ( p 1 a 1 p 3 a 3 . . . p n a n ) + μ ( p 1 a 1 p 2 a 2 . . . p n a n ) ] \mu(p)[\mu(p_{2}^{a_{2}}p_{3}^{a_{3}}...p_{n}^{a_{n}})+\mu(p_{1}^{a_{1}}p_{3}^{a_{3}}...p_{n}^{a_{n}})+\mu(p_{1}^{a_{1}}p_{2}^{a_{2}}...p_{n}^{a_{n}})] μ(p)[μ(p2a2p3a3...pnan)+μ(p1a1p3a3...pnan)+μ(p1a1p2a2...pnan)]
      中括号内的部分恰好就是 f ( T ) f(T) f(T),于是这部分值就为 μ ( p ) f ( T ) \mu(p)f(T) μ(p)f(T)

      最后一项即 T T T本身的莫比乌斯函数值,于是此时有
      f ( T p ) = μ ( p ) f ( T ) + μ ( T ) f(Tp)=\mu(p)f(T)+\mu(T) f(Tp)=μ(p)f(T)+μ(T)

    最后在数论分块的时候需要区间求和 f ( T ) f(T) f(T),给 f ( T ) f(T) f(T)做一个前缀和即可 O ( 1 ) O(1) O(1)求出

    // #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    using namespace std;
    using ll=long long;
    const int N=1e7+5;
    
    bool nt[N];
    int prime[N],cnt,mu[N],f[N];
    
    void make_prime()
    {
    	mu[1]=1;
    	for(int i=2;i<=10000000;i++)
    	{
    		if(!nt[i]) prime[++cnt]=i,mu[i]=-1,f[i]=1;
    		for(int j=1;j<=cnt&&i*prime[j]<=10000000;j++)
    		{
    			nt[i*prime[j]]=true;
    			if(i%prime[j]==0)
    			{
                    mu[i*prime[j]]=0;
    				f[i*prime[j]]=mu[i];
    				break;
    			}
    			else
                {
                    mu[i*prime[j]]=mu[i]*mu[prime[j]];
                    f[i*prime[j]]=mu[i]+f[i]*mu[prime[j]];
                }
    		}
    	}
        for(int i=1;i<=10000000;i++) f[i]+=f[i-1];
    }
    
    int main()
    {
    	make_prime();
    	int t; cin>>t;
    	while(t--)
    	{
    		int n,m; ll ans=0; scanf("%d%d",&n,&m);
    		if(n>m) swap(n,m);
    		for(int l=1,r;l<=n;l=r+1)
    		{
    			r=min(n/(n/l),m/(m/l));
    			ans+=1ll*(n/l)*(m/l)*(f[r]-f[l-1]);
    		}
    		printf("%lld\n",ans);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
  • 相关阅读:
    opencv实践项目-图像拼接
    鸿蒙开发游戏(一)---大鱼吃小鱼(界面部署)
    simpleini库的介绍和使用(面向业务编程-格式处理)
    van-dialog弹窗异步关闭-校验表单
    echarts根据x轴数据长度判断是否倾斜展示/柱状图上方显示数字
    云计算现在前景如何?
    云原生之容器编排实践-SpringBoot应用Docker化
    机器学习-计算数据之间的距离
    【微信小程序入门到精通】— 轮播图你会了么?快速拿下 swiper 和 swiper-item
    【C++笔记】第十九篇 多态
  • 原文地址:https://blog.csdn.net/stdforces/article/details/127786664