原题链接:点击此处
题意:
第一行输入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;
源程序:
View Code
#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 ",ans); } return 0; }