zoukankan      html  css  js  c++  java
  • BZOJ 2820: YY的GCD [莫比乌斯反演]【学习笔记】

    2820: YY的GCD

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 1624  Solved: 853
    [Submit][Status][Discuss]

    Description

    神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
    傻×必然不会了,于是向你来请教……多组输入

    Input

    第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M

    Output

    T行,每行一个整数表示第i组数据的结果

    Sample Input

    2
    10 10
    100 100

    Sample Output

    30
    2791

    HINT

    T = 10000

    N, M <= 10000000


    和bzoj2705很像http://www.cnblogs.com/candy99/p/6200745.html

    但是n和m不同,不能使用直接欧拉函数的方法

    参考:http://blog.csdn.net/acdreamers/article/details/8542292 && popoqqq课件

    和上一题相同的函数:

      为满足的对数

      为满足的对数

    显然,反演后得到

     

    可以枚举每一个质数,套用上一题的做法,p相当于k,d*p也就是p的倍数了...很像上一题我WT1中的式子

     

    其实d只要枚举到min(n,m)/p

    然而复杂度承受不了,大约n/logn*sqrt(n)

    我们设,那么继续得到

     

    为什么这么做呢?因为这样之后发现F函数与p和d无关了,(要不然枚举p和d也是枚举了T)

    可以提到前面,剩下的那一块可以处理前缀和做到O(1),前面再用除法分块,做到O(sqrt(n))

     

    WT:

    如何求g(T)=Σ{p|T && isprime(p)}miu(T/p)

    法1.

    只需要枚举每个素数,将他的倍数的g更新就可以了

    由于有1/1+1/2+1/3+...+1/n=O(logn)这个结论 因此每个质数枚举时是均摊O(logn)的(*n后好想,是nlogn,但是质数只有n/logn个)

    而质数恰好有O(n/logn)个 因此暴力枚举就是O(n)的

    法2.

    线性筛

    g[i*p[j]]

    当p[j]|i时结果显然为miu(i)

    否则考虑mu(i*p[j]/pp),当p[j]=pp时为mu[i],p[j]!=pp时的所有的和就是-g(i),所以总的结果为mu(i)-g(i)

     枚举质数 4176ms

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=1e7+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    int n,m;
    bool notp[N];
    int p[N],mu[N],g[N];
    void sieve(){
        mu[1]=1;
        for(int i=2;i<N;i++){
            if(!notp[i]) p[++p[0]]=i,mu[i]=-1;
            for(int j=1;j<=p[0]&&i*p[j]<N;j++){
                notp[i*p[j]]=1;
                if(i%p[j]==0){
                    mu[i*p[j]]=0;
                    break;
                }
                mu[i*p[j]]=-mu[i];
            }
        }
        
        for(int j=1;j<=p[0];j++)
            for(int i=p[j];i<N;i+=p[j])
                g[i]+=mu[i/p[j]];
        for(int i=1;i<N;i++) g[i]+=g[i-1];
    }
    ll cal(int n,int m){
        if(n>m) swap(n,m);
        ll ans=0;int r;
        for(int i=1;i<=n;i=r+1){
            r=min(n/(n/i),m/(m/i));
            ans+=(ll)(g[r]-g[i-1])*(n/i)*(m/i);
        }
        return ans;
    }
    int main(int argc, const char * argv[]) {
        sieve();
        int T=read();
        while(T--){
            n=read();m=read();
            printf("%lld
    ",cal(n,m));
        }
        return 0;
    }

     线性筛:3328ms

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=1e7+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    int n,m;
    bool notp[N];
    int p[N],mu[N],g[N];
    void sieve(){
        mu[1]=1;
        for(int i=2;i<N;i++){
            if(!notp[i]) p[++p[0]]=i,mu[i]=-1,g[i]=1;
            for(int j=1;j<=p[0]&&i*p[j]<N;j++){
                notp[i*p[j]]=1;
                if(i%p[j]==0){
                    mu[i*p[j]]=0;
                    g[i*p[j]]=mu[i];
                    break;
                }
                mu[i*p[j]]=-mu[i];
                g[i*p[j]]=mu[i]-g[i];
            }
        }
        for(int i=1;i<N;i++) g[i]+=g[i-1];
    }
    ll cal(int n,int m){
        if(n>m) swap(n,m);
        ll ans=0;int r;
        for(int i=1;i<=n;i=r+1){
            r=min(n/(n/i),m/(m/i));
            ans+=(ll)(g[r]-g[i-1])*(n/i)*(m/i);
        }
        return ans;
    }
    int main(int argc, const char * argv[]) {
        sieve();
        int T=read();
        while(T--){
            n=read();m=read();
            printf("%lld
    ",cal(n,m));
        }
        return 0;
    }
  • 相关阅读:
    ajax处理响应(三)
    ajax起步 (二)
    ajax的使用(一)
    css相关用法
    vue 实例的生命周期
    vue中computed与watch的异同
    文本显示,单行超出和多行超出显示省略号
    vue+mui+html5+ plus开发的混合应用底部导航的显示与隐藏
    addEventListener()与removeEventListener(),追加事件和删除追加事件
    原生js中获取this与鼠标对象以及vue中默认的鼠标对象参数
  • 原文地址:https://www.cnblogs.com/candy99/p/6209609.html
Copyright © 2011-2022 走看看