Naive Great Common Divisor
发布日期:2021-05-07 01:00:48 浏览次数:23 分类:原创文章

本文共 2525 字,大约阅读时间需要 8 分钟。

题目

同标题

题目描述
输入 N N N M ( 2 ≤ N ≤ 1000000000 , 1 ≤ M ≤ N ) M(2\le N\le 1000000000,1\le M\le N) M(2N1000000000,1MN),找出所有满足 1 ≤ x ≤ N 1\le x\le N 1xN gcd ⁡ ( x , N ) ≥ M \gcd(x,N)\ge M gcd(x,N)M x x x的数量。

输入格式
第一行输入数据组数 T ( T ≤ 100 ) T(T\le 100) T(T100),每个数据输入两个整数 N , M N,M N,M

输出格式
对于每组样例,输出一个整数,表示满足条件的 x x x的数量。

思路

暴力枚举 gcd ⁡ ( x , N ) = d \gcd(x,N)=d gcd(x,N)=d 多香啊!

定理: N N N的不同的约数个数是 2 n − 1 2\sqrt{n}-1 2n 1 2 n 2\sqrt{n} 2n 。提示: d d d n d \frac{n}{d} dn最多只有一个小于 n \sqrt{n} n

所以直接把 n n n的约数处理出来,然后枚举这个 d d d

此时,设 x = k d x=kd x=kd,那么 gcd ⁡ ( x , N ) = gcd ⁡ ( k × d , N d × d ) = d ⋅ gcd ⁡ ( k , N d ) \gcd(x,N)=\gcd(k\times d,\frac{N}{d}\times d)=d\cdot \gcd(k,\frac{N}{d}) gcd(x,N)=gcd(k×d,dN×d)=dgcd(k,dN)

所以 gcd ⁡ ( k , N d ) = 1 \gcd(k,\frac{N}{d})=1 gcd(k,dN)=1

我们再求一下 k k k的范围: n ≥ x = k d n\ge x=kd nx=kd,得到 k ≤ N d k\le\frac{N}{d} kdN

这两点综合起来,发现 k k k的不同的取值就是 φ ( N d ) \varphi(\frac{N}{d}) φ(dN)

于是输出就应该为 ∑ d ∣ n , m ≤ d φ ( n d ) \sum_{d|n,m\le d}\varphi(\frac{n}{d}) dn,mdφ(dn)

代码

#include <cstdio>#include <iostream>#include <algorithm>#include <vector>using namespace std;inline int readint(){   	int a = 0, f = 1; char c = getchar();	for(; c<'0' or c>'9'; c=getchar())		if(c == '-') f = -1;	for(; '0'<=c and c<='9'; c=getchar())		a = (a<<3)+(a<<1)+(c^48);	return a*f;}const int MaxN = 1000000;bool isPrime[MaxN+1];int phi[MaxN+1];vector<int> primes;void sievePrime(int n){   	for(int i=2; i<=n; ++i)		isPrime[i] = true;	primes.clear(); phi[1] = 1;	for(int i=2; i<=n; ++i){   		if(isPrime[i]){   			primes.push_back(i);			phi[i] = i-1;		}		for(int j=0,len=primes.size(); j<len and 1ll*i*primes[j]<=n; ++j){   			isPrime[i*primes[j]] = false;			if(i%primes[j] == 0){   				phi[i*primes[j]] = phi[i]*primes[j];				break;			}			phi[i*primes[j]] = phi[i]*phi[primes[j]];		}	}}int getPhi(int n){   	int ppl = 1;	for(int d=2; 1ll*d*d<=n and n>MaxN; ++d){   		if(n%d == 0)			ppl *= (d-1), n /= d;		while(n%d == 0)			ppl *= d, n /= d;	}	if(n > MaxN) ppl *= (n-1);	else ppl *= phi[n];	return ppl;}vector<int> divide(int n){   	vector<int> ys; ys.clear();	for(int i=1; 1ll*i*i<=n; ++i)		if(n%i == 0){   			ys.push_back(i);			if(i != n/i)				ys.push_back(n/i);		}	sort(ys.begin(),ys.end());	return ys;}int main(){   	sievePrime(MaxN);	for(int T=readint(); T; --T){   		int n = readint(), m = readint();		int ans = 0;		vector<int> &&ys = divide(n);		for(vector<int>::iterator i=lower_bound(ys.begin(),ys.end(),m); i!=ys.end(); ++i)			ans += getPhi(n/(*i));		printf("%d\n",ans);	}	return 0;}
上一篇:【学习笔记】后缀数组
下一篇:Python3序列

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2025年04月10日 23时05分41秒