题意:
- 给一个区间边界值很大的区间,但是区间大小较小,求出该区间内所有质数个数。
知识补充:
- 因数枚举:分解一个数n,至于要从1 枚举到 n−−√ 即可,然后把i和 n / i 当做因数加入vector
- 整数分解(把一个整数枚举出其质数基连乘的形式):从2开始枚举质数基,然后每次把该整数尽可能的被当前质数除去最大次数,这样该整数就会变小,极大减少枚举量。注意和map搭配使用,记录每一个质数的个数。
埃式素数筛法的复杂度是: Ologlogn 看做线性也无妨。
求区间 [a,b) 内素数的个数,由于b的最大质数因子小于 b√ 所有先把2到 b√ 内的素数打表,再利用素数筛法,筛除 [a,b) 内所有的合数。
#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int LL;
const int M = 100009,INF = 0x3fffffff;
vector<int> prime;
void get_prime(void) {
bool isprime[1000009];
memset(isprime, 0, 1000009);
for (int i = 2; i <= 1000000; i++) {
if (!isprime[i]) {
prime.push_back(i);
for (int j = i; j <= 1000000; j += i) isprime[j] = true;
}
}
}
int primes(LL a, LL b) {
bool isprime[1000009];
int ans = 0;
memset(isprime, 0 , b - a);
for (int i = 0; i < prime.size() && prime[i] < b; i++) {
int j = 0;
bool find = false;
for (LL k = a; k < b; k++, j++) if (k % prime[i] == 0) { find = true; break; }
if (!find) continue;
for (; j < b - a; j += prime[i]) { isprime[j] = true; if (j + a == prime[i]) ans++; }
}
for (int i = 0; i < b - a; i++) if (!isprime[i]) ans++;
if (a <= 1) ans -= 2 - a;
return ans;
}
int main(void) {
//problem: , address:
LL a, b;
get_prime();
while (~(scanf("%lld%lld", &a, &b))) {
cout << primes(a, b) << endl;
}
return 0;
}