「作业」线性筛素数
A. 【模板】线性筛素数
传送门:水滴
线性筛板子。原理请看这个。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e8 + 10;
int prime[maxn];
bool isPrime[maxn];
void xxs (ll n) {
int cnt = 0;
memset (isPrime, 1, sizeof(isPrime));
isPrime[1] = 0;
for (int i = 2; i <= n; i++) {
if (isPrime[i])
prime[++cnt] = i;
for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
isPrime[i * prime[j]] = 0;
if (i % prime[j] == 0)
break;
}
}
}
int n, q;
int main(){
scanf("%d%d", &n, &q);
xxs (n);
while (q--) {
int k; scanf("%d", &k);
printf("%d\n", prime[k]);
} return 0;
}
B. A % B Problem
传送门:水滴
题目大意:给定正整数 l,r,求区间 [l,r] 中质数的个数。
首先写好线性筛板子。看到 l,r 想到预处理质数数的前缀和。设 ans[i]
表示第 i 个数中有多少质数。分两种情况:
-
第 i 个数是合数,就把
ans[i]
赋值为ans[i - 1]
,没有对答案造成贡献。 -
第 i 个数是质数,就把
ans[i]
赋值为当前质数的个数。
最后判断一下边界情况,如果合法就输出 ans[r] - ans[l - 1]
即可。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
int n, m;
int l, r;
int prime[maxn];
bool isPrime[maxn];
int ans[maxn];
inline void xxs(int n) {
int cnt = 0;
memset(isPrime, 1, sizeof(isPrime));
isPrime[1] = 0;
for (int i = 2; i <= n; i++) {
ans[i] = ans[i - 1];
if (isPrime[i])
prime[++cnt] = i, ans[i] = cnt;
for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
isPrime[i * prime[j]] = 0;
if (i % prime[j] == 0)
break;
}
}
}
int main(){
scanf("%d%d", &n, &m);
xxs(m);
while (n--) {
scanf("%d%d", &l, &r);
if (l > m || l < 1 || r > m || r < 1)
printf("Crossing the line\n");
else
printf("%d\n", ans[r] - ans[l - 1]);
}
return 0;
}
C. 集合
传送门:水滴
题目大意:要求我们在一个区间 [A,B] 中找出几个集合,集合中的数满足是一个大于等于 P 的质因数的个数。
先线性筛,然后用并查集将同质因数的数合并,最后查看有几个祖先即为答案。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int a, b, p;
int prime[maxn];
bool isPrime[maxn];
int fa[maxn];
int cnt;
inline int get(int x) {
return x == fa[x] ? x : fa[x] = get(fa[x]);
}
inline void merge(int x, int y) {
fa[get(x)] = get(y);
}
inline void xxs() {
cnt = 0;
memset(isPrime, 1, sizeof(isPrime));
isPrime[1] = 0;
for (int i = 2; i <= maxn; i++) {
if (isPrime[i])
prime[++cnt] = i;
for (int j = 1; j <= cnt && i * prime[j] <= maxn; j++) {
isPrime[i * prime[j]] = 0;
if (i % prime[j] == 0)
break;
}
}
}
int main() {
xxs();
scanf("%d%d%d", &a, &b, &p);
for (int i = a; i <= b; i++) fa[i] = i;
int pos = lower_bound(prime, prime + cnt, p) - prime;
for (int i = pos; prime[i] <= b; i++) {
for (int j = 2; j * prime[i] <= b; j++) {
if ((j - 1) * prime[i] < a) continue;
merge((j - 1) * prime[i], j * prime[i]);
}
}
int ans = 0;
for (int i = a; i <= b; i++)
if (fa[i] == i) ans ++;
return printf("%d\n", ans), 0;
}