链接:戳这里
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
题意:
给出n,m。找出gcd(n,a)>=m (1<=a<=n) 满足条件的a有多少个
思路:
首先定义数a能被n整除,且a>=m
对于1~n中肯定有许多是a的倍数同样也满足条件 gcd(a*p,n)=a,a>=m 这里的p显然与n/a互质。
欧拉函数计算(1~n/a)素数的个数算贡献
我们来证明为什么是计算与n/a互质 且 贡献没有多余的计算
假设p与n/a不互质,那么gcd(a*p,n)=a,=> (除以a) gcd(p,n/a)!=1 显然与我们想要的gcd(a*p,m)=a矛盾
所以这个数p必然与n/a互质
好,那为什么是算n/a与p互质的个数的贡献呢?
现在gcd(a*p,n)=a,a>=m 需要满足条件,这里的p的取值范围1~n/a之间的,且必须与(n/a)互质
也就是贡献加上euler(n/a)的值了
那么接下来证明为什么没有计算多余的贡献?
设a、b为两个不同的大于等于m的n的约数
假设存在重复 那么就有 a*x = b*y (x是小于等于n/a且与n/a互质的数,y同理)
变形 得到 x*n/b = y*n/a 由于x和n/a互质 所以 x是y的约数(因为两边分解质因数的时候n/a不能分出x的约数 只能是y来分)
不妨设 y = kx(k>1) 则 n/b = k(n/a)
由于y和n/b互质 则kx和n/b互质 但是n/b有个k作为约数 所以他们有公约数k 这显然推出k = 1 于是产生a==b矛盾!
所以不会产生重复
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double lb;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
int euler(ll n){
int res=n;
for(int i=2;i*i<=n;i++){
if(n%i==0){
res=res*(i-1)/i;
while(n%i==0) n/=i;
}
}
if(n>1) res=res*(n-1)/n;
return res;
}
int main(){
int T;
scanf("%d",&T);
int n,m;
while(T--){
scanf("%d%d",&n,&m);
int ans=0;
if(m==1) {
printf("%d\n",n);
continue;
}
for(int i=1;i*i<=n;i++){
if(n%i==0){
if(i>=m) ans+=euler(n/i);
if(n/i!=i && n/i>=m) ans+=euler(i);
}
}
printf("%d\n",ans);
}
return 0;
}