• BZOJ 1101 莫比乌斯函数+分块


    思路:
    题目中的gcd(x,y)=d (x<=a,y<=b)可以转化成
    求:gcd(x,y)=1 (1<=x<=a/d 1<=y<=b/d)

    设 G(x,y)表示x<=a y<=b x,y互质 的数有多少组

    F(a,b,k)表示有多少组x<=a y<=b gcd(x,y)>=k(注意是大于等于K)
    这个很好求啊 就是(a/k)*(b/k)

    G(x,y)=P1*F(a,b,1)+P2*F(a,b,2)+P3*F(a,b,3)+….+Px*F(a,b,x)

    Ans=G(x,y)=ΣPx*(a/x)*(b/x)

    这不就是个容斥原理嘛!
    P就是莫比乌斯函数啊~
    莫比乌斯函数是可以在线性时间内筛出来的~
    这样我们就得到了预处理O(n)单词询问O(n/d)的方法
    但是如果n很大 d很小 这个就是单词O(n)的了
    怎么办呢
    观察 这个式子ΣPx*(a/x)*(b/x) a/x的取值有sqrt(n)种
    b/x的取值有sqrt(n)种
    但是它们乘起来却不是O(n)种 而是sqrt(n)的!
    预处理μ(x) 分块 求一下 完事~

    //By SiriusRen
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define maxn 55555
    int n,a,b,d,ans,pos,tot,mu[maxn],prime[maxn],sum[maxn],vis[maxn];
    void shai(){
        sum[1]=1;
        for(int i=2;i<maxn;i++){
            if(!vis[i])mu[i]=-1,prime[++tot]=i;
            for(int j=1;j<=tot&&i*prime[j]<maxn;j++){
                vis[i*prime[j]]=1,mu[i*prime[j]]=-mu[i];
                if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
            }
            sum[i]=sum[i-1]+mu[i];
        }
    }
    int main(){
        scanf("%d",&n);
        shai();
        while(n--){
            scanf("%d%d%d",&a,&b,&d);
            if(a>b)swap(a,b);
            a/=d,b/=d,ans=0;
            for(int i=1;i<=a;i=pos+1){
                pos=min(a/(a/i),b/(b/i));
                ans+=(sum[pos]-sum[i-1])*(a/i)*(b/i);
            }
            printf("%d
    ",ans);
        }
    }

    这里写图片描述

  • 相关阅读:
    StrictMode 检测应用
    动态设置视图大小
    查看手机CPU每个APP利用率
    获取屏幕尺寸,大于7为平板,小于7为手机
    Charles 抓取https 包
    SparseArray
    Gradle 差异化构建
    HashMap原理
    Gc root 定义
    Java多线程
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6532093.html
Copyright © 2020-2023  润新知