zoukankan      html  css  js  c++  java
  • 【BZOJ】2820: YY的GCD

    【题意】给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对。T<=10^4,N,M<=10^7。

    【算法】数论(莫比乌斯反演)

    【题解】公式推导见DQSSS

    推到ans= Σp是素数 Σd≤mins μ(d) * (n/pd) * (m/pd),mins=min(n/p,m/p)。

    使用枚举取值的方法再枚举素数单次询问复杂度√n*(n/ln n),显然不能满足要求。

    问题在于枚举素数,令T=pd,则:

    ans= ΣT≤mins (n/T) * (m/T)*Σp|T&&p是素数 μ(T/p),mins=min(n,m)。

    后面部分可以枚举素数的倍数预处理出μ前缀和,复杂度O((n/ln n)*ln n)即O(n)。

    每次询问再枚举取值O(√n)解决。

    总复杂度O(T*√n+n)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn=10000010,N=10000000;
    int miu[maxn],mius[maxn],prime[maxn],tot;
    ll s[maxn];
    bool mark[maxn];
    void pre(){
        miu[1]=1;
        for(int i=2;i<=N;i++){
            if(!mark[i])miu[prime[++tot]=i]=-1;
            for(int j=1;j<=tot&&i*prime[j]<=N;j++){
                mark[i*prime[j]]=1;
                if(i%prime[j]==0)break;
                miu[i*prime[j]]=-miu[i];
            }
        }
        for(int i=1;i<=tot;i++){
            for(int j=prime[i];j<=N;j+=prime[i])mius[j]+=miu[j/prime[i]];
        }
        for(int i=1;i<=N;i++)s[i]=s[i-1]+mius[i];
    }
    int main(){
        pre();
        int T,n,m;
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            int pos=0,mins=min(n,m);ll ans=0;
            for(int i=1;i<=mins;i=pos+1){
                pos=min(n/(n/i),m/(m/i));
                ans+=(s[pos]-s[i-1])*(n/i)*(m/i);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    将枚举两个数改为枚举乘积和其中一个,即T和p|T,后面的p|T可以O(n log n)贡献处理前缀和。

  • 相关阅读:
    循环神经网络
    相似度计算(余弦距离/欧式距离)
    最常见Linux操作
    注意力机制总结
    随机打乱数组算法、蓄水池算法
    6.1 数据结构---树(遍历)
    Node.js调用C/C++
    linux中nmcli命令详解
    stylus入门使用方法
    webpack CommonsChunkPlugin详细教程
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8274302.html
Copyright © 2011-2022 走看看