• 洛谷 P2568 GCD(欧拉定理 | | 莫比乌斯反演)


    题目描述

    给定整数N,求1<=x,y<=N(N<=1e7)且Gcd(x,y)为素数的数对(x,y)有多少对.

    输入输出样例

    输入样例#1:
    4
    输出样例#1:
    4

    题解

    此题有两种解法。
    1.欧拉函数
    很明显,可以枚举素数p,计算n/p的phi,然后统计出来乘以2,最后再特判x==y且x,y为素数的情况。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    int n,cnt;
    ll phi[10000001];
    int vis[10000001];
    int prime[10000001];
    ll sum=0;
    void init(){
        for(register int i=2;i<=n;i++){
            if(!vis[i]){
                prime[++cnt]=i;
                phi[i]=i-1;
            }
            for(register int j=1;j<=cnt&&i*prime[j]<=n;j++){
                int k=i*prime[j];
                vis[k]=1;
                if(i%prime[j]==0){
                    phi[k]=phi[i]*prime[j];
                    break;
                }
                else{
                    phi[k]=phi[i]*(prime[j]-1);
                }
            }
            phi[i]=phi[i-1]+(phi[i]<<1);
        }
    }
    int main(){
        scanf("%d",&n);
        init();
        for(register int i=1;i<=cnt;i++){
            sum+=phi[n/prime[i]]+1;
        }
        printf("%lld",sum);
        return 0;
    }

    2.莫比乌斯反演
    当1<=x<=n,1<=y<=m时,欧拉函数的求法就不管用了,这时我们可以用莫比乌斯反演来简化计算。
    我们设

    f(n)=d|n[gcd(x,y)==d]

    F(n)=d|nf(d)

    根据莫比乌斯反演定理可得
    f(n)=d|nμ(n/d)F(d)

    F(d)的值可以通过它的定义发现
    F(d)=(n/d)(n/d)

    f(n)=d|nμ(n/d)((n/d)(n/d))

    枚举质数,暴力累计答案即可。
    (此方法在洛谷70,TLE*3,在bzojAC)
    此题升级版:洛谷P3455

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define ll long long
    using namespace std;
    int mu[10000001];
    int cnt;
    bool vis[10000001];
    int prime[5000001];
    void init(int n){
        mu[1]=1;
        for(int i=2;i<=n;i++){
            if(!vis[i]){
                prime[++cnt]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
                int k=i*prime[j];
                vis[k]=1;
                if(i%prime[j]){
                    mu[k]=-mu[i];
                }
                else{
                    mu[k]=0;
                    break;
                }
            }
        }
    }
    int main(){
        ll n;
        scanf("%lld",&n);
        init(n);
        ll ans=0;
        for(ll i=1;i<=cnt;i++){
            ll lim=n/prime[i];
            for(ll j=1;j<=lim;j++){
                ans+=mu[j]*((lim)/j)*((lim)/j);
            }
        }
        printf("%lld",ans);
        return 0;
    }

    考虑优化。
    我不会推公式,就借dalao的公式一用吧(滑稽)
    这里写图片描述
    然后就可以分块搞了。。。
    (其实跑的还挺快的,时间和欧拉几乎相同)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define ll long long
    using namespace std;
    int mu[10000001];
    int cnt;
    bool vis[10000001];
    int prime[5000001];
    void init(int n){
        mu[1]=1;
        for(int i=2;i<=n;++i){
            if(!vis[i]){
                prime[++cnt]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=cnt&&i*prime[j]<=n;++j){
                int k=i*prime[j];
                vis[k]=1;
                if(i%prime[j]){
                    mu[k]=-mu[i];
                }
                else{
                    mu[k]=0;
                    break;
                }
            }
            mu[i]+=mu[i-1];
        }
    }
    int main(){
        ll n;
        scanf("%lld",&n);
        init(n);
        ll ans=0;
        for(ll k=1;k<=cnt;++k){
            ll m=n/prime[k];
            ll j;
            for(ll i=1;i<=m;i=j+1){
                ll mul=m/i;
                j=min(m,m/mul);
                ans+=mul*mul*(mu[j]-mu[i-1]);
            }
        }
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    关于lockkeyword
    关于多层for循环迭代的效率优化问题
    Android 面试精华题目总结
    Linux基础回想(1)——Linux系统概述
    linux源代码编译安装OpenCV
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem B. Matrix Fast Power
    校赛热身 Problem B. Matrix Fast Power
    集合的划分(递推)
  • 原文地址:https://www.cnblogs.com/stone41123/p/7581263.html
Copyright © 2020-2023  润新知