hdu 2588

http://acm.hdu.edu.cn/showproblem.php?pid=2588


又一道欧拉函数题,题目要求小于等于n且与n的最大公约数大于等于m的所有数的个数

欧拉函数只能求出小于n且与n互质的所有数的个数,但是无法求出最大公约数是否大于m

但是 我们可以这样想 设a为大于等于m的n的一个约数,那么euler(n/a)表示的就是所有小于a与a互质的数的个数,设任一个数为x,那么这些数再乘以a就有gcd(n,x*a) = a;

所以我们可以想到答案为所有n大于等于m的约数ai的euler(n/ai)之和

但是还有一个问题 这些数是否会重复呢?答案是否定的

设a、b为两个不同的大于等于m的n的约数

假设存在重复 那么就有 a*x = b*y (x是小于等于n/a且与n/a互质的数,y是n/b的。。)

变形 得到 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矛盾!

所以不会产生重复


最后注意一下 m=1的时候答案就是n 直接加结果貌似不对


贴段代码

#include <string.h>
#include <iostream>
#include <stdio.h>
#include <math.h>

using namespace std;

int euler(int n){
    int temp = n;
	int sq_n = sqrt(n+0.5);
	int ans = n;
	for(int i = 2;i<=sq_n;i++){
		if(n%i==0){
			ans = ans/i*(i-1);
			while(n%i==0) n/=i;
		}
	}
	if(n>1) ans = ans/n*(n-1);
	return ans;
}

int main(void){
	//freopen("","r",stdin);
	int t;
	scanf("%d",&t);
	while(t--){
		int n,m;
		scanf("%d %d",&n,&m);
		if(m==1){
		    printf("%d\n",n);
		    continue;
		}
		int ans = 0;
		int sq_n = sqrt(n+0.5);
		for(int i = 2;i<=sq_n;i++){
			if(n%i==0){
			    if(i>=m) ans+=euler(n/i);
				if(n/i>=m) ans+=euler(i);
			}
		}
		if(n!=1&&sq_n*sq_n==n&&sq_n>=m) ans-=euler(sq_n);
		printf("%d\n",ans+1);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值