题目地址:http://acm.fafu.edu.cn/problem.php?id=1011
Description:
The problem is very simple,your job is just to calculate the sum of primes from the first prime to the Nth prime.
Input:
The input consists multiple cases. Each line contains a N(1<=N<=1000000).
Output:
For each N,output the result of this problem that describe before.
Sample Input:
1
3
5
Sample Output:
2
10
28
题目意思是说输入一个N,计算从第1个素数到第N个素数的和。注意看题目,N最大可能达到100万。也就是说测试数据有可能让你计算从第1个素数到第100万个素数的和。这题的难点在于如何快速筛选出素数。如果我们用枚举法(或普通的方法),那必定会超时。这里,我要介绍一个大素数筛子(专门筛选素数)。
我们知道2,5,7...这些都是素数。而素数的倍数一定不是素数,那么我们只要将已经判断过的素数的倍速删去即可。举个例子:2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20。
(1)判断2是否素数;是;将2的倍数删去后剩:
2,3,5,7,9,11,13,15,17,19
(2)判断3是否素数;是;将3的倍数删去后剩:
2,3,5,7,11,13,17,19
(3)判断5是否素数;是;将5的倍数删去后剩........以此类推。
那么代码该如何实现呢?假设我们要求第1个到第100个素数可以定义一个isPrime数组来标记是否为素数。再确定数组大小之前,我们要先判断一下第100个素数可能有多大。这里我们先假设为400。
for(i = 2; i <= 20; ++i)//这里i<=sqrt(400)即400的开方 if(isPrime[i]) for(j = 2*i; j <= 400; j+=i) // i+i 就是 i 的倍数 isPrime[j] = false; //素数的倍数置零
标记完,isPrime[i]等于1的,就是素数,而且该素数就是其下标。接下来就可以获取素数了。
for(i = 2,k=1; i <= 400; ++i) if(map[i]) prime[k++] = i; //从下标1开始存放第一个素数
if(map[i]) prime[k++] = i;//从下标1开始存放第一个素数
剩下的工作就轻松多了!整体代码如下:
#include<cstdio> #include<cstring> #define N 1000000 #define maxn 16000000 bool map[maxn]; __int64 prime[N+5]={0}; __int64 sum[N+5]={0}; int main(void) { memset(map,true,sizeof(map)); int i,j,n,k=1; for(i = 2; i <= 4000; ++i) if(map[i]) for(j = 2*i; j < maxn; j+=i)//将素数的倍数置零 map[j] = false; for(i = 2,j = 1; i <= maxn && j <= N; ++i) if(map[i]) { prime[k++] = i;//从下标1开始存放第一个素数 sum[j] = sum[j-1]+prime[j]; ++j;//sum[k]为第1~k个素数的和 } while(scanf("%d",&n) != EOF) printf("%I64d\n",sum[n]); return 0; }
这个代码中,我用map数组表示状态(即isPrime数组的功能),用prime数组来存放素数。sum数组来存结果。如sum[10]的值为第1个素数到第10个素数的和。