Luogu1835 素数密度_NOI导刊2011提高(04

这题有两种做法,一种是 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>
#include <cmath>
using namespace std;

typedef long long ll;
const int MAX_SQRT = 65536, MAX_N = 1000005;

int lef, rig, tot_prime, ans;
int prime[MAX_SQRT];
bool not_prime[MAX_SQRT], GG[MAX_N];

inline void get_prime(int top) {
    not_prime[1] = true;
    for (ll i = 2; i <= top; ++i) {
        if (!not_prime[i]) prime[++tot_prime] = i;
        for (int j = 1; j <= tot_prime && 1ll * i * prime[j] <= top; ++j) {
            not_prime[i * prime[j]] = true;
            if (i % prime[j] == 0) break;
        }
    }
    return;
}

int main() {
    get_prime(46341);
    scanf("%d%d", &lef, &rig);
    for (int i = 1; i <= tot_prime && prime[i] <= rig; ++i) {
        for (ll j = ll(ceil(double(lef) / prime[i])) * prime[i]; j <= rig; j += prime[i]) {
            if (j != prime[i]) GG[j - lef] = true;
        }
    }
    for (ll i = lef; i <= rig; ++i) ans += (!GG[i - lef]);
    printf("%d\n", ans);
    return 0;
}

  

posted @ 2018-11-05 13:29  EvalonXing  阅读(159)  评论(0编辑  收藏  举报