模板 - 数学 - 数论 - 线性筛
线性筛质数,可以通过输出ptop之后调整p数组的大小。pm[i]表示i的最小质因子,pk[i]表示含有i的最小质因子的幂。其他的积性函数主要依靠pk的值来求解,比如现在枚举的是t,求出了他的最小质因子的幂pk[t],那么t/pk[t]与pk[t]显然是互质的。当t==pk[t]时,则t是p[j]的幂次,一般积性函数在质数的幂次都要特殊求解,不过欧拉函数和莫比乌斯函数可以直接从低一级的幂次转移过来。当t!=pk[t]时,直接分解成两个互质的数的乘积。要注意这个算法的空间消耗巨大。
1ex内的质数数量:
1e1|4
1e2|25
1e3|168
1e4|1229
1e5|9592
1e6|78498
1e7|664579
1e8|5761455
其他常见的上界:
2e5|17984
2e6|148933
2e7|1270607
5e5|41538
5e6|348513
5e7|3001134
第一个严格大于上界的最小质数连乘:
2*3*5 = 30 > 10 = 1e1
2*3*5*7 = 210 > 100 = 1e2
2*3*5*7*11 = 2310 > 1000 = 1e3
2*3*5*7*11*13 = 30030 > 10000 = 1e4
2*3*5*7*11*13*17 = 510510 > 100000 = 1e5
2*3*5*7*11*13*17*19 = 9699690 > 1000000 = 1e6
2*3*5*7*11*13*17*19*23 = 223092870 > 10000000 = 1e7
注意这个是严格大于,假如保证在上界以内的话事实上是少一个的。
const int MAXN = 1e7; int p[MAXN + 5], ptop; int pm[MAXN + 5], pk[MAXN + 5]; void sieve() { int n = MAXN; pm[1] = 1; pk[1] = 1; for(int i = 2; i <= n; i++) { if(!pm[i]) { p[++ptop] = i; pm[i] = i; pk[i] = i; } for(int j = 1; j <= ptop; j++) { int t = i * p[j]; if(t > n) break; pm[t] = p[j]; if(i % p[j]) { pk[t] = pk[p[j]]; } else { pk[t] = pk[i] * p[j]; break; } } //printf("i=%d pm=%d pk=%d\n", i, pm[i], pk[i]); } //printf("ptop=%d\n",ptop); /*for(int i=1;i<=ptop;++i) printf("%d:%d\n",i,p[i]);*/ }
判断一个数是不是质数只需要判断pm[i]==i。判断一个数是不是质数的幂只需要判断pk[i]==i。当然1是奇异的,特殊处理就可以了。
很多时候只是需要质数,那么这样写比较省空间,也比较快。
const int MAXN = 1e7; int p[MAXN + 5], ptop; bool pn[MAXN + 5]; void sieve() { int n = MAXN; pn[1] = 1; for(int i = 2; i <= n; i++) { if(!pn[i]) p[++ptop] = i; for(int j = 1; j <= ptop; j++) { int t = i * p[j]; if(t > n) break; pn[t] = 1; if(i % p[j] == 0) break; } } printf("ptop=%d\n", ptop); /*for(int i = 1; i <= ptop; ++i) printf("%d:%d\n", i, p[i]);*/ }