1. 埃氏筛
mk[i] = true 表示 i 不是素数。时间复杂度好像(OrzOrz)是 O(√N) 。有的代码可能会写 for (j = i*2; ... ) 其实不用,因为 i*2, i*3 ... i*(i-1) 都在之前的循环里讨论过了,所以 j 从 i*i 开始扫就可以了。但整体而言两种写法时间复杂度是一样的。
1 mk[1] = true; 2 for (i = 2; i <= N; ++i) { 3 if (mk[i]) continue; 4 for (j = i*i; j <= N; j += i) mk[i] = true; 5 }
1. 欧拉筛
时间复杂度是 O(N) ,因为每个数只会被它最小的素约数筛到。
1 void euler(int mx) 2 { 3 int i, j, cnt = 0; 4 for (i = 2; i <= mx; ++i) { 5 if (!mark[i]) P[++cnt] = i, phi[i] = i-1; 6 for (j = 1; j <= cnt && i*P[j] <= mx; ++j) { 7 mark[i*P[j]] = true; 8 if (!(i % P[j])) { phi[i*P[j]] = phi[i] * P[j]; break; } 9 phi[i*P[j]] = phi[i] * (P[j]-1); 10 } 11 } 12 return; 13 }
2. 单个 phi 值计算
1 int phi(int v) 2 { 3 if (v == 1) return 1; 4 int ans = v, i; 5 for (i = 2; i*i <= v; ++i) { 6 if (v % i) continue; 7 ans -= ans / i; 8 while (!(v % i)) v /= i; 9 } 10 if (v > 1) ans -= ans / v; 11 return ans; 12 }