NKOJ P3684 GCD的个数

来源:互联网 发布:cad软件是什么软件 编辑:程序博客网 时间:2024/06/04 23:18

题目导引:http://oi.nks.edu.cn/zh/Problem/Details/3684

问题描述

给定两个正整数N,M, 求满足下列两个条件的X的个数:
条件1:1<=X<=N
条件2:gcd(X,N)>=M

输入格式

一行,两个整数N和M

输出格式

一行,一个整数,表示所求结果

样例输入 1

10 2

样例输出 1

6










样例输入 2

10000 72

样例输出 2

260










提示

2<=N<=1000000000, 1<=M<=N

题目分析:

题目要求小于等于已知N的正整数IN的最大公约数不小于M的个数。

那么,显然可以将N,I分解为他们一个公共数与其他数的乘积,

即:N=T*AI=T*B

显然应当满足:A>=B,并且A,B互质

那么我们要求的就转化为了T>=MB的个数了,而因为A>=B,并且A,B互质,所以这个个数就相当于φ(A)-1,而这里其实可以优化代码,进行折半查找。

我们在枚举I的时候,当I<sqrt(N),那么我们不妨假设T=N/I,当I>sqrt(N)之后,必然有对应的A=N/I,那么很显然,当N%I==0的时候,会出现T*A=N。所以我们就只需要枚举sqrt(N)种情况,而与之对应的情况就是N/I

#include <stdio.h>#include <math.h>#define LL long longusing namespace std;LL N,M;LL Ans;LL Euler(LL n)//欧拉函数 {        LL res=n,a=n;      for(LL i=2ll;i*i<=a;i++){        if(a%i==0){            res=res/i*(i-1);               while(a%i==0) a/=i;        }      }      if(a>1) res=res/a*(a-1);    return res;  }int main(){scanf("%lld%lld",&N,&M);LL I,J,K;LL Temp=sqrt(N);for(I=2ll;I<=Temp;I++)//进行查找 {if(N%I==0){if(I>=M)Ans+=Euler(N/I);if((N/I)>=M)Ans+=Euler(I);}}if(Temp*Temp==N)Ans-=Euler(Temp);//防止完全平方数重复计算 printf("%lld",Ans+1);//算上自己本身 return 0;}