ACM:数论专题(2)——Eular质数筛法

  题目要求:
    题目要求给定一个数字n,求在区间[2, n]范围内素数的个数。

解答:
    本题还是比较简单的。主要利用了素数最基本的一个性质,即:素数只能被1和其本身整除。因此,如果能为某个数字找到一个除1和它本身以外的因数,那么它一定不是素数。
    因此,开设一个大小为n的标记数组is_prime, 开始时其值均为true,然后从2开始扫描,首先2,是一个素数,因此is_prime[2] = true, 并且所有2的倍数一定不是素数,那么就将所有2的倍数对应的is_prime数组的元素置为false,即:is_prime[2*k] = false。
    以此类推,扫描数组中的每一个元素3、4、5....,在每次扫描过程中,将每个数字的倍数对应的is_prime数组的元素置为false,知道is_prime数组的数字全部被扫描。
    接下来,扫描一遍is_prime数组,如果某个元素is_prime[k] = true,那么就表明在扫描k之前的所有数字均不能是is_prime[k]置为false,也就表明:除1以外的所有小于k的数字均不能整除k,那么k就是一个素数。因此统计is_prime数组中true的数目就是[2, n]范围内的素数的数目。 
    
    另外,需要说明的是:本题目的n的范围是[2, 1000000],而表示一个数字是不是素数用一个比特即可标识,因此,一个char类型的变量就可以标识8个数字。因此对于1000000的范围,只需要用大小为125000的char数组即可,为了标识方便,我们将数组的标识从0开始。那么就需要125001个char元素。因此:对于每一个数字n,它在char数组中对应的元素就是:is_prime[n / 8], 而对应的比特位就是元素is_prime[n / 8]的第n % 8 位二进制位。 


输入输出格式:
    输入:输入数字n标识要求的范围。 
    输出:输出一个数字,表示[2,n]范围内素数的个数。

数据范围:
     n≤2≤1000000

程序代码:

/****************************************************/
/* File        : Hiho_Week_93.cpp                   */
/* Author      : Zhang Yufei                        */
/* Date        : 2016-04-11                         */
/* Description : HihoCoder ACM program. (submit:g++)*/
/****************************************************/

#include

/*
 * The main program.
 */
int main(void) {
	char is_prime[125001] = {0};
	int weight[8] = {1, 2, 4, 8, 16, 32, 64, 128};
	
	int n;
	scanf("%d", &n);
	int count = 0;
	
	for(int i = 2; i <= n; i++) {
		int r = is_prime[i / 8];
		int c = r >> i % 8;
		c %= 2;
		if(c == 0) {
			count++;
			for(int j = 2; i * j <= n; j++) {
				is_prime[i * j / 8] |= weight[i * j % 8];
			}
		}
	}
	
	printf("%d\n", count);
	
	return 0;
}


你可能感兴趣的:(ACM)