Luogu1835 素數密度_NOI導刊2011提高(04
阿新 • • 發佈:2018-11-05
這題有兩種做法,一種是 Miller-Rabin 直接暴力做
還有一種是正解的篩法
先說 Miller-Rabin
就直接上板子就行了
但是 1e6 帶一堆 log 顯然不穩
就 “記憶化” 一下,把每個詢問過的數字的倍數直接處理掉
直接上真的會 T
直接把詢問過的數字倍數的抹掉就能過了
其實應該是把質數的倍數抹掉感覺能少一點常數
程式碼:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cctype> #include <cstdio> using namespace std; typedef long long ll; const int MAX_SIZ = 2000005; int lef, rig, ans; int prime[3] = {2, 7, 61}; bool not_prime[MAX_SIZ]; inline int fast_pow(int bot, int top, int mod) { register int ret = 1; while (top) { if (top & 1) ret = 1ll * ret * bot % mod; top >>= 1; bot = 1ll * bot * bot % mod; } return ret; } inline bool dvd_chk(int bot, int top, int mod) { register int tmp; while (!(top & 1)) { tmp = fast_pow(bot, top, mod); if (tmp == 1) top >>= 1; else if (tmp == mod - 1) return true; else return false; } return true; } inline bool Test(int a) { if (a <= 1) return false; if (a == 2) return true; if (!(a & 1)) return false; for (int i = 0; i < 3; ++i) { if (prime[i] == a) return true; if (fast_pow(prime[i], a - 1, a) != 1) return false; if (!dvd_chk(prime[i], a - 1, a)) return false; } return true; } int main() { scanf("%d%d", &lef, &rig); register ll tmp; for (ll i = lef; i <= rig; ++i) { if (not_prime[i - lef] || i == 1) continue; if (Test(i)) { ++ans; tmp = (2ll * i); while (tmp <= rig) { not_prime[tmp - lef] = true; tmp += tmp; } } else not_prime[i - lef] = true; } printf("%d\n", ans); return 0; }
然後是正解的做法
直接線性篩肯定是不可行的
考慮怎麼搞掉特別大的合數
2147483647 的 mindiv 也不過才 46341
所以直接用 mindiv 去刪掉區間內的數就行了,其他的數不用管
這樣它大概是個 len * ln len 的
由於這並不是調和級數,分母都是質數,而且並不是 1e6 內的所有
所以它還要小很多
總之比 n log n 快
程式碼:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cctype> #include <cstdio> using namespace std; typedef long long ll; const int MAX_SIZ = 2000005; int lef, rig, ans; int prime[3] = {2, 7, 61}; bool not_prime[MAX_SIZ]; inline int fast_pow(int bot, int top, int mod) { register int ret = 1; while (top) { if (top & 1) ret = 1ll * ret * bot % mod; top >>= 1; bot = 1ll * bot * bot % mod; } return ret; } inline bool dvd_chk(int bot, int top, int mod) { register int tmp; while (!(top & 1)) { tmp = fast_pow(bot, top, mod); if (tmp == 1) top >>= 1; else if (tmp == mod - 1) return true; else return false; } return true; } inline bool Test(int a) { if (a <= 1) return false; if (a == 2) return true; if (!(a & 1)) return false; for (int i = 0; i < 3; ++i) { if (prime[i] == a) return true; if (fast_pow(prime[i], a - 1, a) != 1) return false; if (!dvd_chk(prime[i], a - 1, a)) return false; } return true; } int main() { scanf("%d%d", &lef, &rig); register ll tmp; for (ll i = lef; i <= rig; ++i) { if (not_prime[i - lef] || i == 1) continue; if (Test(i)) { ++ans; tmp = (2ll * i); while (tmp <= rig) { not_prime[tmp - lef] = true; tmp += tmp; } } else not_prime[i - lef] = true; } printf("%d\n", ans); return 0; }