有时候会求在大区间[L,R]内的素数个数,但是一般R-L不会很大,因此可以求[1,√R]中的素数来筛[L,R]中的素数。用求出的素数来筛[L,R]中的合数。因为L,R过大,开出的数组大小一般为最大的R-L。
例题①:https://vjudge.net/problem/POJ-2689
注意:1不为素数的情况。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxl = 5e4;
bool vis[maxl];
int p[maxl], tot;
int ans[1000005];
ll prime[1000005];
void init() {
vis[0] = vis[1] = true;
for (int i = 2; i < maxl; i++) {
if (!vis[i])p[tot++] = i;
for (int j = 0; j < tot && i * p[j] < maxl; j++) {
vis[i * p[j]] = true;
if (i % p[j] == 0)break;
}
}
}
int main(void) {
init();
ll L, R;
while (~scanf("%lld %lld", &L, &R)) {
memset(ans, 0, sizeof(ans));
for (int i = 0; i < tot; i++) {
for (ll j = max(2LL, (L - 1) / p[i] + 1) * p[i]; j <= R; j += p[i])
if (j - L >= 0)ans[j - L] = 1;
}
if (L == 1)ans[0] = 1;
int minn = inf, maxx = -1, cnt = 0;
for (int i = 0; i <= R - L; i++)
if (!ans[i])prime[cnt++] = i;
int out[4] = { -1,-1,-1,-1 };
for (int i = 1; i < cnt; i++) {
if (minn > prime[i] - prime[i - 1]) {
minn = prime[i] - prime[i - 1];
out[0] = prime[i - 1]; out[1] = prime[i];
}
if (maxx < prime[i] - prime[i - 1]) {
maxx = prime[i] - prime[i - 1];
out[2] = prime[i - 1]; out[3] = prime[i];
}
}
if (minn == inf || out[0] == -1) { printf("There are no adjacent primes.\n"); continue; }
printf("%lld,%lld are closest, %lld,%lld are most distant.\n", L + out[0], L + out[1], L + out[2], L + out[3]);
}
return 0;
}
例题②:http://acm.hdu.edu.cn/showproblem.php?pid=6069
题意:求区间[L,R]中每个元素的K次方的约数个数之和,模998244353。
因为是大区间,预先求出1-1e6的素数,利用约数个数定理。两层循环,外层遍历每个素数,内层遍历在该区间内的该素数的倍数,不断分解质因子。注意若分解后的结果不为1,说明剩下的是一个大于1e6的素数。
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxl = 1e6 + 1;
const ll mod = 998244353;
int p[maxl], tot, num[maxl];
bool vis[maxl];
ll val[maxl];
void init() {
vis[0] = vis[1] = true;
for (int i = 2; i < maxl; i++) {
if (!vis[i])p[tot++] = i;
for (int j = 0; j < tot && i * p[j] < maxl; j++) {
vis[i * p[j]] = true;
if (i % p[j] == 0)break;
}
}
}
ll qpow(ll a, ll b) {
ll res = 1;
while (b){
if (b & 1)res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int main(void) {
init();
int T;
for (scanf("%d", &T); T--;) {
ll L, R, K;
scanf("%lld %lld %lld", &L, &R, &K);
for (int i = 0; i <= R - L; i++)num[i] = 1, val[i] = L + i;
for (int i = 0; i < tot; i++) {
//遍历在区间[L,R]内所有p[i]的倍数
ll LL = ((L - 1) / p[i] + 1) * p[i];
for (ll j = LL; j <= R; j += p[i]) {
ll cnt = 0;
while (val[j - L] % p[i] == 0)val[j - L] /= p[i], cnt++;
num[j - L] = num[j - L] * (cnt * K % mod + 1) % mod;
}
}
for (int i = 0; i <= R - L; i++)if (val[i] != 1)num[i] = num[i] * (K + 1) % mod;
ll ans = 0;
for (int i = 0; i <= R - L; i++)ans = (ans + num[i]) % mod;
printf("%lld\n", ans);
}
return 0;
}