标签:去掉 需要 合数 分享 prim efi eof nbsp style
判断一个数n是否是素数,众所周知可以用O(sqrt(n))的方法。
但是如果要求很多个数,这个方法就不太好了。(比如所有小于n的数,复杂度就是O(n1.5)。)
埃拉托斯特尼筛法,大家都听说过。从2到n,去掉每个数的倍数,剩下来的就是质数。
不过这个方法会重复删除,比如6是2、3的倍数,会被删2次,因子越多,删的次数就越多。
改进之后的线性筛保证每个数只被最小的质因子删,所以是O(n)的。
#include<cstdio> #include<cstring> #define MAXN 100005 #define MAXL 1299710 int prime[MAXN]; int check[MAXL]; int tot = 0; memset(check, 0, sizeof(check)); for (int i = 2; i < MAXL; ++i) { if (!check[i]) { prime[tot++] = i; } for (int j = 0; j < tot; ++j) { if (i * prime[j] > MAXL) { break; } check[i*prime[j]] = 1; if (i % prime[j] == 0) { break; } } }
(代码来自:https://www.cnblogs.com/grubbyskyer/p/3852421.html)
tot是计数用的,prime保存质数,check是判断是否是质数。
1.任意一个合数 A = p1p2...pn,(其中p1<=p2<=...<=pn) ,i=p2p3...pn时会删掉。
2.A只会被p1删掉。若i是prime[j]的倍数,A不会被p[j+1]删掉,当i=A/p[j+1]时,i%p[j+1]==0,break。如果不退出,A就被p[j+1]删了。
可以看出,这个方法需要额外的prime数组。而埃氏筛不必要。
顺便可以求欧拉函数
#include<cstdio> #include<cstring> #define MAXN 100005 #define MAXL 1299710 int prime[MAXN]; int check[MAXL]; int phi[MAXL]; int tot = 0; phi[1] = 1; memset(check, 0, sizeof(check)); for (int i = 2; i < MAXL; ++i) { if (!check[i]) { prime[tot++] = i; phi[i] = i - 1; } for (int j = 0; j < tot; ++j) { if (i * prime[j] > MAXL) { break; } check[i*prime[j]] = 1; if (i % prime[j] == 0) { phi[i*prime[j]] = phi[i] * prime[j]; break; }else { phi[i*prime[j]] = phi[i] * (prime[j]-1); } } }
n为质数,phi(n)=n-1
n为合数,进行质因数分解。n=p1k1p2k2...pnkn。
标签:去掉 需要 合数 分享 prim efi eof nbsp style
原文地址:https://www.cnblogs.com/azureice/p/euler-sieve.html