浙大版《C语言程序设计(第3版)》题目集
练习4-11 统计素数并求和 (20 分)
本题要求统计给定整数M和N区间内素数的个数并对它们求和。
输入格式:
输入在一行中给出两个正整数M和N(1≤M≤N≤500)。
输出格式:
在一行中顺序输出M和N区间内素数的个数以及它们的和,数字间以空格分隔。
输入样例1:
10 31
输出样例1:
7 143
二、题解
这题数据量很小,暴力即可, 也可用筛法。
朴素筛法:
2 3 4 5 6 7 8 9 10 11 12
把所有数的倍数筛掉,如把2的倍数筛掉,剩下2 3 5 7 9 11, 把3的倍数筛掉,剩下2 3 4 7 11,把4的倍数筛掉,以此类推。时间复杂度为O(log n);
如果一个数P没有被筛掉,说明2 ~ (P - 1)没有一个数是P的约数,P是一个素数。
埃氏筛法:每一个合数都可以被分解为质因子相乘,如30 = 2 * 3 * 5;所以我们只需要用质因子来筛去倍数就可以了。相较于朴素筛法提高了时间效率。时间复杂度为O(log log n);
欧拉筛(线性筛):
无论是朴素筛法还是埃氏筛法都有一些数被重复筛选,降低了时间效率。因为每个合数只有一个最小质因子,若只使用他的最小质因子来进行筛选就可以避免重复筛选的现象。用一个数组来维护一个确定的素数列,从小到大去枚举素数。
st[i * primes[j]] = 1;
因为我们是从小到大去枚举质数的,所以 i * primes[j]
一定会被他的最小质因数primes[j]
筛去。
if(i % primes[j] == 0) break;
当i % primes[j] == 0
时,即i = primes[j] * x
,若此时不去break,则下一个数z = i * primes[j + 1] = primes[j] * x * primes[j + 1]
,primes[j + 1]
并不是z的最小质因子,会被重复筛选。举个例子,i = 6 = 2 * 3
,则下一个数 z = i * 3 = 2 * 3 * 3
,会被2 * 9
和 3 * 6
重复筛去。
c代码
#include <stdio.h>
int N = 510;
int primes[510], st[510];
int cnt = 0;
//朴素筛法
void P() {
for (int i = 2; i <= N; i++) {
if(!st[i]) primes[cnt++] = i;
for (int j = i + i; j <= N; j += i)
st[j] = 1;
}
}
//埃氏筛法
void P() {
for (int i = 2; i <= 510; i++) {
if(!st[i]) {
primes[cnt++] = i;
for (int j = i + i; j < N; j += i)
st[j] = 1;
}
}
}
//欧拉筛
void P() {
for (int i = 2; i < N; i++) {
if(!st[i]) primes[cnt++] = i;
for (int j = 0; j < cnt && primes[j] * i < N ; j++) {
st[i * primes[j]] = 1;
if(i % primes[j] == 0) break;
}
}
}
int main() {
P();
int m, n, sum = 0, cnt = 0;
scanf("%d%d", &m, &n);
int ans = 0;
for (int i = 0; primes[i] <= n; i++) {
if(primes[i] >= m && primes[i] <= n) {
sum += primes[i];
ans++;
}
}
printf("%d %d\n", ans, sum);
return 0;
}