题意:
13195的所有质因数为5、7、13和29。
600851475143最大的质因数是多少?
思路:
600851475143大概是6e11,如果纯暴力找它的每个因子,然后再判断每个因子是不是质数,时间复杂度大约是1e22,家用电脑估计一个小时也跑不完吧~
有些人继续优化,说可以用线性筛求[2,600851475143]范围内的质数,然后找最大满足是600851475143因子的质数。这样时间复杂度是1e11,家里电脑依然跑不完~而且线性筛需要开两个1e11的数组分别用来判断是否为质数和存质数,我们无法开这么大的数组。
这时候,我们就需要明白一点,600851475143的临界值是多少?嗯,这个数的临界值为(int)(sqrt(600851475143)),为什么呢?
仔细想一下,如果最大质因子小于等于(int)(sqrt(600851475143)),那么我们只需要线性筛前(int)(sqrt(600851475143))就可以找出它的最大质因子。
如果最大质因子大于(int)(sqrt(600851475143)),那么600851475143中不可能同时存在两个大于(int)(sqrt(600851475143))的质因子(如果存在,两个质因子相乘就大于600851475143啦),所以我们可以通过除以(int)(sqrt(600851475143))以内所有600851475143的质因子,最后剩下的数,就是大于(int)(sqrt(600851475143))的质因子。
而(int)(sqrt(600851475143))为775146,用线性筛求775146范围内的质数时间复杂度只有1e6左右,家用电脑一秒钟以内肯定能求出来~
代码如下:
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <inttypes.h>
#define ll int64_t
#define d int32_t
#define len 775150
ll n = 600851475143;
//prime[]用于存素数
d prime[len];
//choose[i]用于判断i是否为素数,0是,1不是
bool choose[len];
ll init() {
ll maxx = 0; //用来存储最大的质因子
prime[0] = 0; //用来记录质数个数
memset (choose, 0, sizeof(choose));
for (d i = 2; i < len; i ++) {
if (!choose[i]) {
//如果i是素数就添加到prime中
prime [++prime[0]] = i;
//如果i是不断缩小的n的因子,则n循环累除i
if(n % i == 0) {
while (n % i == 0) {
n /= i;
}
//更新质因子的最大值
maxx = i;
}
}
//线性筛的性质
for (d j = 1; j <= prime[0] && i * prime[j] < len; j++) {
choose[i * prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
//如果此时n不为1,说明最大质因子大于(int)sqrt(600851475143)
if (n != 1) {
maxx = n; //那么更新最大质因子
}
return maxx; //最后返回值即为结果
}
int main() {
ll ans = init();
printf("%" PRId64"\n", ans);
return 0;
}
最后输出答案为6857 ,Over~
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢!