【代码超详解】UVA 10006 Carmichael Numbers(Carmichael 数)(60 ms)

这篇博客详细解析了UVA 10006题目的Carmichael Numbers问题,介绍了如何通过质数的埃氏筛法和质数判定来解决。博主分享了在编程过程中遇到的TLE问题,并提供了AC代码,该代码运行时间为60 ms。
摘要由CSDN通过智能技术生成

一、题目描述

已知:费马(Fermat)小定理 设 n 为质数,则对任意整数 a 都有

我们依次令 a = 2, 3, …, n - 1,那么当 n 是质数时,这些代入都令上式成立。
但当 n 是某些合数时,仍然能够通过费马检验。这些合数称为 Carmichael 数。
已知 2 < n < 65 000,输入多行,每行一个 n,判断 n 是不是 Carmichael 数。
当 n = 0 时,输入结束。

Sample Input

1729
17
561
1109
431
0

Sample Output

The number 1729 is a Carmichael number.
17 is normal.
The number 561 is a Carmichael number.
1109 is normal.
431 is normal.

二、算法分析说明与代码编写指导

质数的埃氏筛法

1、用途:快速选出一定数量的质数。

2、算法内容:
埃拉托斯特尼(Eratosthenes)筛法(埃氏筛法) 要筛选出不大于n的质数,排除sqrt(n)以内全部质数的倍数即可。
(Eratosthenes(前276—前194),古希腊数学家)
设需要生成前若干个质数,prime数组用于存储已经验证为质数的数。
设a为当前正在验证是否为质数的正整数,t = sqrt(a)为需要试除的范围。
用已知的质数去除a,如果能整除,a就有除了1和a本身以外的因数,终止当前的判断,准备判断a+1。
为什么只用试除到t = sqrt(a)呢,因为因数是一对一对的,例如:
100 的因数有:1 2 4 5 10 20 25 50 100。我们发现,1 * 100 = 2 * 50 = 4 * 25 = 5 * 20 = 10 * 10。
如果验证到sqrt(a)后,还没有发现第3个a的因数,自然也不会再有了。
换句话说,还是以100为例子,如果找出了因数2,就可以计算出因数50。如果找到了因数4,就可以计算出因数25。
如果验证了某个数d不是a的因子,那么d的倍数也不是a的因子。
比如2不是 a 的因子,那么4 6 8 …… 都不用验证了。比如3不是 a 的因子,那么6 9 12 …… 都不用验证了。
如果要验证是否为a的因子的数d是质数,那么在之前验证过的数及其倍数都不是这个质数d的因数,也就是说d还没有用于验证过。
可见,用质数试除是不能避免的。对于合数来说,如果已知它的一个质因数不是a的因子,那么这个合数也不用再验证是否为a的因子。意即,要用这个合数去除a,就相当于用a的每个质因数去除a。如果某个质因数不能整除a,那么这个合数也不能整除a。
从几个角度都啰嗦完了,相信总有一种角度适合你的理解。

质数的判定

1、用途:迅速判定一个数是否为质数。
2、算法内容:
用埃氏筛法打质数表,打表结果保存在prime数组中。然后判断要验证是否为质数的整数x是否在表的范围内。如果是,在prime数组内二分搜索x,搜到就是质数,搜不到就不是。如果x超出了表的范围,就验证x是不是已经打表的质数的倍数。如果都不是,x就是质数。

3、代码实现:(含埃氏筛法打表,有时候int / unsigned的范围不够用,此时需要自己换类型)
要求:采用本参考代码时,需要先包含头文件algorithm和cmath(有的编译器的algorithm不含sqrt),且声明一个prime数组用于存储已经验证的质数,以及using namespace std; 传入的参数是需要生成的质数的数量。前2个质数2、3必须要先写入prime数组。额外建立一个变量_PTy,其类型与prime数组的类型相同,以便decltype关键字自动侦测类型。此外,x的类型不能大于prime数组的类型。

4、注意事项:
x不能超过最大已打表质数的平方,否则会返回错误的结果,从而WA。
5、时间复杂度:
设要判定的数为n。当n在质数打表范围时,二分搜索并返回搜索结果,时间复杂度为O(log n)(也可以写成O(ln n))。
当n不在质数打表范围sqrt(n)时,最坏情况是需要用π(sqrt(n))个质数去验证(π(x)是不大于整数x的质数的数量)。所以判定一个数n是否为质数的时间复杂度不超过

对本题,要先判定是否为质数再进行费马检验,否则会TLE。昨天T了我一整天,真见鬼。

一个原因是:如果数据中质数比较多,那么这些质数会全部通过费马测试,从2到n-1的费马测试一次要O(nlogn)的时间复杂度,如果数据比较多,就会超时。

三、AC 代码(60 ms)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值