zoukankan      html  css  js  c++  java
  • P3455 [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 aaa, bbb and ddd, find the number of integer pairs (x,y)(x,y)(x,y) satisfying the following conditions:

    1≤x≤a1le xle a1xa,1≤y≤b1le yle b1yb,gcd(x,y)=dgcd(x,y)=dgcd(x,y)=d, where gcd(x,y)gcd(x,y)gcd(x,y) is the greatest common divisor of xxx and yyy".

    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 nnn (1≤n≤50 0001le nle 50 0001n50 000),denoting the number of queries.

    The following nnn lines contain three integers each: aaa, bbb and ddd(1≤d≤a,b≤50 0001le dle a,ble 50 0001da,b50 000), separated by single spaces.

    Each triplet denotes a single query.

    输出格式:

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

    输入输出样例

    输入样例#1: 
    2
    4 5 2
    6 4 3
    输出样例#1: 
    3
    2

    Solution:

      本题莫比乌斯反演板子题

      题意就是求$sum_limits{i=1}^{ileq n}sum_limits{j=1}^{jleq m} gcd(i,j)==d$。

      令$f(n)$表示满足约束条件的且$gcd(i,j)=n$的个数,令$F(n)$表示满足约束条件的且$n|gcd(i,j)$的个数。

      于是有$F(n)=sum_limits{n|d} {f(d)}$,这个式子显然可以反演,得到$f(n)=sum_limits{n|d} {mu(frac{d}{n})*F(d)}$。

      又因为对于数$x$,显然$n$中含有$frac{n}{x}$个$x$的倍数,同理$m$中有$frac{m}{x}$个,所以$F(x)=frac{n}{x}*frac{m}{x}$。

      则原式变为$f(d)=sum_limits{d|k}^{kleq min(n,m)}{mu(frac{k}{d})frac{n}{k}frac{m}{k}}$。

      令$t=frac{k}{d}$,则原式变为$f(d)=sum_limits{t=1}^{frac{min(n,m)}{d}}{frac{n}{td}frac{m}{td}}$,对于$lfloor frac{n}{td} floor lfloor frac{m}{td} floor$直接数论分块求就好了,所以还得预处理下$mu$的前缀和。

      时间复杂度$O(qsqrt n)$。

    代码:

    /*Code by 520 -- 9.10*/
    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define RE register
    #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    const int N=50005;
    int n,a,b,d,mu[N],prime[N],cnt;
    bool isprime[N];
    
    int gi(){
        int a=0;char x=getchar();
        while(x<'0'||x>'9')x=getchar();
        while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+(x^48),x=getchar();
        return a;
    }
    
    il void pre(){
        mu[1]=1;
        For(i,2,50000){
            if(!isprime[i]) mu[i]=-1,prime[++cnt]=i;
            for(RE int j=1;j<=cnt&&prime[j]*i<=50000;j++){
                isprime[i*prime[j]]=1;
                if(i%prime[j]==0) break;
                mu[i*prime[j]]=-mu[i];
            }
        }
        For(i,1,50000) mu[i]+=mu[i-1];
    }
    
    int solve(){
        if(a>b) swap(a,b);
        a/=d,b/=d;
        int pos=0,ans=0;
        for(int i=1;i<=a;i=pos+1){
            pos=min(a/(a/i),b/(b/i));
            ans+=(mu[pos]-mu[i-1])*(a/i)*(b/i);
        }
        return ans;
    }
    
    int main(){
        pre();
        n=gi();
        while(n--){
            a=gi(),b=gi(),d=gi();
            printf("%d
    ",solve());
        }
        return 0;
    }
  • 相关阅读:
    《人月神话》读后感*part1
    《程序员修炼之道——从小工到专家》阅读笔记*part6
    Java课06
    《程序员修炼之道——从小工到专家》阅读笔记*part5
    《程序员修炼之道——从小工到专家》阅读笔记*part4
    Java课堂测试——输出单个文件中的前N个最常出现的英语单词
    四则运算自动出题系统——网页版
    关于JAVA项目中的常用的异常处理情况
    《程序员修炼之道——从小工到专家》阅读笔记*part3
    《程序员修炼之道——从小工到专家》阅读笔记*part2
  • 原文地址:https://www.cnblogs.com/five20/p/9633662.html
Copyright © 2011-2022 走看看