bit 1049 Relatives

Relatives

时间限制: 1秒  内存限制: 64M

ProblemDescription

Given n, a positive integer, how many positive integers less than or equal to n are relatively prime to n ? Two integers a and b are relatively prime if thereare no integers x > 1, y > 0, z > 0 such that a = xy and b = xz.

Input

There are several test cases. For each test case, standard input contains a line with n <= 1,000,000,000. A line containing 0 follows the last case.

Output

For each test case there should be single line of output answering the question posed above.

Sample Input

7

12

0

Sample Output

6

4

刚开始想法是先用线性筛素数伐打一个素数表和利用公式求欧拉函数,没想到刚开始因为估计素数个数不是太多,开的数组太小,导致内存引用无效,后来加大数组,还是tle了,然后参看了一下大神的blog开始改用质因数分解定理,边分解质因数,边约分的策略,但是由于细节处理不当还是tle了,最后看看了大神的细节处理,又改写了一遍代码,最终ac了。

#include <stdio.h>
int ans;
void Eu(int n){
	for(int i = 2; i * i <= n;++i){
		if(!(n%i)){
			ans *= i - 1;
			n /= i;
			while(!(n%i)){
				ans *= i;n/=i; 
			} 
		}
	}
	if(n > 1){
		ans *= n -1;
	}
	return ;
}
int main(){
	int n;
	while(scanf("%d",&n),n){
		ans = 1;
		Eu(n);
		printf("%d\n",ans);
	}
	return 0;
}


没处理好的部分是: i  <=   n这一部分。和 i*i <=n的最大优点是在处理大质数的地方可以省很多的的时间,比如17上面的循环只需执行5次即可,而下面的执行17次。而在每一次的求质因数的时候,都能体现这一点。当质因数很多时时间上的差别就体现出来了,都是利用质因数分解定理,但是因为一点细节处理就导致时间上很大的差别。

void Eu(int n){
	for(int i = 2;n-1;++i){
		if(!(n%i)){
			ans *= i - 1;
			n /= i;
			while(!(n%i)){
				ans *= i;n/=i; 
			} 
		}
	}
	
	return ;
}


这次学习的收获还有就是,又熟悉了一边素数表的线性求法:

//线性筛选素数的方法
    for(int i = 2; i <4000;++i){
        if(!not_prime[i]){
            prime[p_len++] = i; 
        }
        for(int j = 0; j < p_len;++j){
            not_prime[i * prime[j]] = 1;
            if(!(i % prime[j])){
                break;  
            }
        }
    }


本来第一次看到这个求n(这里是40000)以内的素数表,实在去年暑期集训的时候在北交的acm对的大神blog里看到的,但是当时没理解怎么回事,后来有自己写过一次也没理解透是怎么回事,写的时候还是边参考这别人的代码便自己写,但是始终没想太明白为什么是对的,昨天在火车上回学校的时候好好想了一下这个原因为什么会是素数的,其实可以利用质因数唯一分解定理,和 埃拉托斯特尼筛 就可以证明这个筛法是线性的,每一个被筛到的数,只被筛过一次。

质因数唯一分解定理说明任何 数  = 一个质数 prime[j] * 一个数i(可以为质数可以为非质数),当i %prime[j] = 0 时后面的就不用再算了其实后

prime[j+1] * i  可以转化为 prime[j] * (大于i的数)的乘积;

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值