zoukankan      html  css  js  c++  java
  • [bzoj2820]YY的GCD

    来自FallDream的博客,未经允许,请勿转载,谢谢。

    ------------------------------------------------------------------------

    $T<=10000$组数据,每次给定$n,mleqslant 10^{7}$,求$1leqslant xleqslant n,1leqslant yleqslant m,gcd(x,y)是质数$的(x,y)有多少对。

    首先枚举质数p,很容易得到式子$$Ans=sum_{p=1}^{n}sum_{i=1}^{lfloor frac{n}{p} floor}sum_{i=1}^{lfloor frac{m}{p} floor}sum_{d|i,d|j}mu(d)$$

    然后我们从d看待这个式子,得到$$Ans=sum_{p=1}^{n}sum_{d=1}^{lfloor frac{n}{p} floor}mu(d)lfloor frac{n}{pd} floorlfloor frac{m}{pd} floor$$

    这样还是太麻烦了,我们设T=pd,枚举T.对于每个T,$lfloor frac{n}{T} floor$和$lfloor frac{m}{T} floor$不变,而$mu(d)$则只有在作为它的因数的时候出现,所以得到式子

    $$Ans=sum_{T=1}^{n}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floorsum_{p|T}mu(frac{T}{p})$$

    然后$sum_{p|T}mu(frac{T}{p})$这东西直接枚举质数,质数数量$n/logn$,每个质数均摊$logn$,预处理复杂度O(n),然后每个询问可以在$sqrt(n)$时间内完成。

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define MN 10000000
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    int mu[MN+5],f[MN+5],s[MN],num=0;
    bool b[MN+5];
    
    ll calc(int n,int m)
    {
        ll sum=0;
        for(int i=1,last;i<=n;i=last+1)
        {
            last=min(n/(n/i),m/(m/i));
            sum+=1LL*(f[last]-f[i-1])*(n/i)*(m/i);
        }
        return sum;
    }
    
    int main()
    {
        mu[1]=1;
        for(register int i=2;i<=MN;i++)
        {
            if(!b[i])
            {
                mu[i]=-1;f[i]=1;
                s[++num]=i;
            }
            for(register int j=1;s[j]*i<=MN;j++)
            {
                b[s[j]*i]=1;
                if(i%s[j]==0) break;
                else mu[s[j]*i]=-mu[i];
            }
        }
        for(int i=1;i<=num;i++)
        {
            for(register int j=s[i]<<1;j<=MN;j+=s[i])
                f[j]+=mu[j/s[i]];
        }
        for(int i=2;i<=MN;i++) f[i]+=f[i-1];
        int T=read();
        while(T--)
        {
            int n=read(),m=read();
            if(n>m)swap(n,m);
            printf("%lld
    ",calc(n,m));
        }
        return 0;
    }
  • 相关阅读:
    ui5 call view or method from another view
    vuejs helloworld
    vuejs v-model
    vuejs v-bind
    vuejs on
    vuejs fatherandson
    vuejs scope
    vuejs keep-alive
    VLAN虚拟局域网
    网线的制作
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj2820.html
Copyright © 2011-2022 走看看