• [POI2007] ZAP-Queries (莫比乌斯反演)


    [POI2007] ZAP-Queries

    题目描述

    Byteasar the Cryptographer works on breaking the code of BSA (Byteotian Security Agency). He has alreadyfound out that whilst deciphering a message he will have to answer multiple queries of the form"for givenintegers aa, bb and dd, find the number of integer pairs (x,y)(x,y) satisfying the following conditions:

    1le xle a1≤x≤a,1le yle b1≤y≤b,gcd(x,y)=dgcd(x,y)=d, where gcd(x,y)gcd(x,y) is the greatest common divisor of xx and yy".

    Byteasar would like to automate his work, so he has asked for your help.

    TaskWrite a programme which:

    reads from the standard input a list of queries, which the Byteasar has to give answer to, calculates answers to the queries, writes the outcome to the standard output.

    FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。

    输入输出格式

    输入格式:

    The first line of the standard input contains one integer nn (1le nle 50 0001≤n≤50 000),denoting the number of queries.

    The following nn lines contain three integers each: aa, bb and dd(1le dle a,ble 50 0001≤d≤a,b≤50 000), separated by single spaces.

    Each triplet denotes a single query.

    输出格式:

    Your programme should write nn lines to the standard output. The ii'th line should contain a single integer: theanswer to the ii'th query from the standard input.

    输入输出样例

    输入样例#1:

    2
    4 5 2
    6 4 3

    输出样例#1:

    3
    2

    Solution

    预备知识:莫比乌斯反演,整除分块

    不会的看这位dalao的博客莫比乌斯反演

    本蒟蒻的整除分块

    根据题意

    [ans=sum_{i=1}^a sum_{j=1}^b [{gcd(i,j)=d}] ]

    [ans=sum_{i=1}^{a/d} sum_{j=1}^{b/d}[gcd(i,j)=1] ]

    下面就是反演

    [ans=sum_{i=1}^{a/d} sum_{j=1}^{b/d} sum_{p|gcd(i,j)}mu(p) ]

    但是这样枚举还是(O(n^2)),所以我们换一个变量枚举,把最后一个求和提到前面,因为p既是i的因子又是j的因子,所以枚举范围就是(min(a/d,b/d)),那么继续推公式

    [ans=sum_{p=1}^{min(a/d,b/d)}{mu(p)} sum_{i=1}^{a/d} sum_{j=1}^{b/d} lfloorfrac{a}{p imes d} floor lfloorfrac{b}{p imes d} floor ]

    如果对于后面的式子不理解,可以这么看,令(x=a/d,y=b/d)
    (p)(x,y)的一个因子,在(x)的范围内有(lfloorfrac{x}{p} floor)(p)的倍数,对于(y)同理,所以每个因子(p)都有(lfloorfrac{x}{p} floorlfloorfrac{y}{p} floor)的贡献

    而对于后面的两个求和我们是可以用前缀和预处理出来的,这个时候是可以做到(O(n))了,但是由于多组数据,所以我们发现,对于一段连续的p,因为a和b的值是确定的,所以(lfloorfrac{a}{p imes d} floorlfloorfrac{b}{p imes d} floor)的值也是确定的,这中间有许多重复的值,那么我们就可以使用整除分块优化到(O(sqrt n))

    (有错误欢迎指出)

    Code

    #include<bits/stdc++.h>
    #define lol long long
    #define il inline
    #define rg register
    #define Min(a,b) (a)<(b)?(a):(b)
    #define Max(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    
    const int N=5e4+10;
    
    void in(int &ans)
    {
        ans=0; int f=1; char i=getchar();
        while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
        while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0', i=getchar();
        ans*=f;
    }
    
    int n,m,d,tot,ans,T;
    int mu[N],sum[N],prime[N];
    bool vis[N];
    
    il void get_mu() {
        mu[1]=1;
        for(int i=2;i<=N-10;i++) {
            if(!vis[i]) prime[++tot]=i,mu[i]=-1;
            for(int j=1;j<=tot && prime[j]*i<=N-10;j++) {
                vis[i*prime[j]]=1;
                if(i%prime[j]==0) break;
                else mu[i*prime[j]]=-mu[i];
            }
        }
        for(int i=1;i<=N-10;i++) sum[i]=sum[i-1]+mu[i];
    }
    
    int main()
    {
        in(T); get_mu();
        while(T--) {
            in(n),in(m),in(d); int nn=n/=d,mm=m/=d,ans=0;
            for(rg int i=1,pos,p=Min(n,m);i<=p;i=pos+1) {
                pos=Min(n/(n/i),m/(m/i));
                ans+=(sum[pos]-sum[i-1])*(nn/i)*(mm/i);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    【项目】项目180
    【项目】项目179
    【项目】项目182
    【项目】项目183
    Java线程与多线程
    MySQL中datetime与timestamp的区别
    SpringBoot整合WebScoket显示进度条
    java记录程序执行时间之StopWatch
    Map基本分类
    Java新特性扩展之List集合操作
  • 原文地址:https://www.cnblogs.com/real-l/p/9628232.html
Copyright © 2020-2023  润新知