HDU 2588 GCD

原题链接:点击此处

题意:

  第一行输入T,表示有T组数据。然后每一行输入N和M,分别表示所要求数的范围为1~N,比较值为M。
 题目意思很简单,就是求解,在数的范围内X∈[1~N],存在多少个X使得GCD(X,N)>=M,统计X符合要求的个数。
 用膝盖骨想想也知道,如果直接暴力遍历N次,每次操作的复杂度高达10^9,肯定会超时的。常规的方法肯定不行。
 

思路: 

我们仔细观察可得,N=a*d,X=b*d。(d即为N与X的最大公约数),题意要求的便是d≥m的情况。
  转换一下思维:因为X=b*d,而题意要求的是d≥m的情况有多少,换句话即是,要求有多少个b。再来看看,N=a*d,X=b*d。
  即a与b互质,那么便可使用欧拉函数了,欧拉函数的定义是:a的欧拉函数便是与a互质并且小于a的所有数的个数。
  但是单单枚举a的欧拉函数还是会超时,那怎么办呢?可以采用二分的方法。
  当i<√N时,我们假设d=N/i,那么此时,a=i;
  如此可得当i>√N时,有a=n/i,d=i;
  当i=√N时,a*d=N;
 
源程序:
#include <iostream>
#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;
           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\n",ans);
    }
    return 0;
}
View Code

 

 
posted @ 2016-08-06 15:34  君子酱  阅读(168)  评论(0编辑  收藏  举报