HDU 2588 GCD(欧拉函数)

思路:

1.题意是给出nnmm,让我们找出有多少个x(1<=x<=n)x(1<=x<=n)满足gcd(n,x)>=mgcd(n,x)>=m
2.设nnxx的最大公约数是dd,则我们可以将nnxx表示成
{n=pdx=qd egin{cases} n=p*d\ x=q*d end{cases}
且我们可以得知ppqq互质且q<=pq<=p,因此我们需要求出在此时dd确定的情况下有多少个qq存在即可,即求pp的欧拉函数;
3.接着我们的目标就是求出对于每一个d(d>=m)d(d>=m),与之对应的pp的欧拉函数,最后将它们相加即可;
4.可能有些人会有疑问(比如说我),题目问xx有多少种取值,我们就简单的遍历所有pp,将这些pp的欧拉函数相加就好了吗?不同的dd对应不同的pp,而同一个pp也对应许多不同的qq,有没有可能这些情况中,计算出来的xx值有重复?
答案是不会的。我们来证明一下,假设
{n=p1d1x1=q1d1n=p2d2x2=q2d2x1=x2 egin{cases} n=p1*d1\ x1=q1*d1\ n=p2*d2\ x2=q2*d2\ x1=x2 end{cases}
则会有
{p1d1=p2d2q1d1=q2d2 egin{cases} p1*d1=p2*d2\ q1*d1=q2*d2 end{cases}
则有p1=p2q1q2p1=frac{p2*q1}{q2},此时q1q2q1 eq q2,因此必有q1q1的一个或多个质因子包含在p1p1中,这与q1p1q1p1互质相矛盾,因此xx的值不会重复;

代码:

#include<iostream>
#include<vector>
using namespace std;
int n,m;
vector<int> v;
void cal_divisor(int n){  //which is greater than m or equals to m
	for(int i=1;i*i<=n;i++) if(n%i==0){
			if(i>=m) v.push_back(i);
			if(i!=n/i&&n/i>=m) v.push_back(n/i); 
	}
}
int eular(int n){
	int ans=n;
	for(int i=2;i*i<=n;i++) if(n%i==0){
		ans-=ans/i;
		while(n%i==0) n/=i;
	}
	if(n>1) ans-=ans/n;
	return ans;
}
int solve(){
	if(m==1) return n;
	v.clear();
	cal_divisor(n);
	int ans=0;
	for(auto x:v) ans+=eular(n/x);
	return ans;
}
int main(){
	int t; cin>>t;
	while(t--){
		cin>>n>>m;
		cout<<solve()<<'
';
	}
	return 0;
}
原文地址:https://www.cnblogs.com/yuhan-blog/p/12308791.html