• HDOJ GCD 2588【欧拉函数】


    GCD

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 1294    Accepted Submission(s): 583



    Problem Description
    The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6.
    (a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem:
    Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.
     

    Input
    The first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.
     

    Output
    For each test case,output the answer on a single line.
     

    Sample Input
    3 1 1 10 2 10000 72
     

    Sample Output
    1 6 260


    题意:

    计算1-N区间里有多少数和N的GCD是大于M的。


    解题思路:

    直接计算绝对超时,所以要想到採用一些定理来进行优化。

    ①我们先看两个数  N = a*b,X= a*d。由于gcd ( N , X ) = a  所以b,d这两个数互质。又由于d能够是不论什么一个小于b的数。

    所以d值数量的的多少就是b的欧拉函数值。

    所以,我们能够枚举a,然后去求b。然后再求b的欧拉函数值。

    ②可是假设单纯这样所有枚举的话依然会超时,所以我们要想一个办法去优化它。

    我们能够折半枚举。这里的折半并非二分的意思。


    我们先看,我们枚举时,当i<sqrt(n),如果a=n / i, 当i>sqrt(n)之后 有b=n/i,我们观察到当n%i==0时,会出现一种情况,就是a*b==n。所以我们就能够仅仅须要枚举sqrt(n)种情况,然后和它相应的情况就是 n/i。

    我们这样的枚举时间会快许多。

    AC代码:

    #include <stdio.h>
    #include <math.h>
    #include <vector>
    #include <queue>
    #include <string>
    #include <string.h>
    #include <stdlib.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int euler(int n)
    {
        int res=n;
        for(int i=2;i*i<=n;i++){
            if(n%i==0){
               res=res/i*(i-1);
               while(n%i==0) n/=i;
            }
        }
        if(n>1) res-=res/n;
        return res;
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            int n,m;
            scanf("%d%d",&n,&m);
            int ans=0;
            for(int i=1;i*i<=n;i++){
                if(n%i==0){
                    if(i>=m)ans+=euler(n/i); //计算sqrt(n)左边的
                    if(n/i>=m&&i*i!=n) ans+=euler(i);//计算sqrt(n)右边的i*i==n时。在上个语句已经运行
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    


  • 相关阅读:
    webserver的使用
    vs2010旗舰版中.net framework 4安装不成功的解决办法
    测量距离
    Mybatis初学习
    Mybatis的一些优化
    开博想法
    matplotlib 画图中的basemap安装问题
    Ubuntu 提示sudo: java: command not found解决办法
    django 中静态文件项目加载问题
    Velocity组装Xml报文
  • 原文地址:https://www.cnblogs.com/llguanli/p/6961269.html
Copyright © 2020-2023  润新知