素数专题

#include <iostream>
#include <cmath>

using namespace std;
const int nMax = 10000000;
int isPrime[nMax];
int prime[nMax];
int factor[nMax];
int len;


void f1()//朴素筛选
{
	int n;//求[1, n]之间的素数
	scanf("%d", &n);
	len = 0;
	memset(isPrime, 0, sizeof(isPrime));
	isPrime[0] = isPrime[1] = 1;
	int i;
	for(i = 2; i <= n; ++ i)
	{
		if(!isPrime[i])
		{
			prime[len ++] = i;
			isPrime[i] = 1;
			__int64 j;
			for(j = (__int64)i * i; j <= n; j += i)//这里i * i会越界
				isPrime[j] = 1;
		}
	}
}

void f2()//线性筛选。在f1上进行改装,每次查找合数时,使用该合数的最小质因子寻找。速度可提高2倍,但是我感觉不太出来
{
	int n;//求[1, n]之间的素数
	scanf("%d", &n);
	len = 0;
	memset(isPrime, 0, sizeof(isPrime));
	isPrime[0] = isPrime[1] = 1;
	int i;
	for(i = 2; i <= n; ++ i)
	{
		if(!isPrime[i])
			prime[len ++] = i;
		int j;
		for(j = 0; j < len && i * prime[j] <= n; ++ j)
			//每次更新一个i,则对所有素数遍历一次。如果发现i是其中素数的倍数,则跳出循环,这样避免重复运算
		{
			isPrime[i * prime[j]] = 1;
			if(i % prime[j] == 0)
				break;
		}
	}
}

int max(int a, int b)
{
	return a > b ? a : b;
}

void f3()//区间内求素数,两点,第一:两数相乘筛选出所有的合数。第二:使用移动数组做标记
{
	int a, b;//求区间[a,b]之间的所有素数
	scanf("%d%d", &a, &b);
	if(a == 1) a ++;//1的时候需要特殊判断,因为永远标记不到
	int m = sqrt(b + 0.5);
	int i;
	for(i = 2; i <= m; ++ i)
	{
		int j;
		for(j = max(i, a / i); j <= b / i; ++ j)
			if(i * j - a >= 0)
				isPrime[i * j - a] = 1;
	}
	len = 0;
	for(i = a; i <= b; ++ i)
		if(!isPrime[i - a])
			prime[len ++] = i;

}

void f4()//最小质因数,函数与f2()很相似
{
	int n;//求[1,n]所有数的质因数
	scanf("%d", &n);
	memset(isPrime, 0, sizeof(isPrime));
	len = 0;
	int i;
	factor[1] = 1;
	for(i = 2; i <= n; ++ i)
	{
		if(!isPrime[i])
		{
			prime[len ++] = i;
			factor[i] = i;
		}
		int j;
		for(j = 0; j < len && i * prime[j] <= n; ++ j)
		{
			isPrime[i * prime[j]] = 1;
			factor[i * prime[j]] = prime[j];
			if(i % prime[j] == 0)
				break;
		}
	}
	for(i = 1; i <= n; ++ i)
	{
		printf("i = %d, factor = %d\n", i, factor[i]);
	}
}

void print()
{
	int i;
	for(i = 0; i < len; ++ i)
	{
		printf("%d\t", prime[i]);
		if((i + 1) % 5 == 0)
			printf("\n");
	}
	printf("\n");
}

int main()
{
	/*
	f1();
	print();
	f2();
	print();
	f3();
	print();*/
	f4();
	return 0;
}

参见:

http://hi.baidu.com/czyuan_acm/blog/item/8a6f7d88187acd9fa4c2721f.html

http://hi.baidu.com/czyuan_acm/blog/item/444a9fa8cecdd9bacb130c2c.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值