超越欧拉的质数递推算法
  • 板块学术版
  • 楼主wangchenyi
  • 当前回复101
  • 已保存回复101
  • 发布时间2022/1/29 21:38
  • 上次更新2023/10/28 10:06:19
查看原帖
超越欧拉的质数递推算法
631814
wangchenyi楼主2022/1/29 21:38

超越欧拉筛法的质数递推算法

算法代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define maxnyxzs 60000010
#define maxnyxfzchs 60000010
using namespace std;
long long gn(){/*get number*/
	char ch=getchar();
	long long fh=1,x=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-')fh=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<3)+(x<<1)+ch-'0';
		ch=getchar();
	}
	return (fh==1)?x:-x;
}
long long n;
long long a[maxnyxzs]={0,2},aa[maxnyxzs];
long long cfs=2/*乘法式的值*/,nc=3/*next_chengfashi 乘法式的下一个质数*/,nci=2/*next_chengfashi_i 乘法式的下一个质数的坐标*/;
long long top=2,dl=1/*duilie_long,队列长度*/ ;
long long tmp;
long long hs[maxnyxfzchs];

void shuru(){
	n=gn();
}
void clac(){
	while(1){
		//cout<<"step1"<<endl;
		while(1){
			if(a[top]==-1){
				top--; 
				continue;
			}
			if(top<nci)break;
			tmp=cfs-a[top];
			if(tmp>n)return;
			//cout<<"--------"<<endl;
			if(tmp>a[dl]){
				++dl;
				a[dl]=tmp;
			}
			top--; 
		}
		tmp=cfs-1;
		if(tmp>a[dl]){
			++dl;
			a[dl]=tmp;
		}
		tmp=cfs+1;
		if(tmp>a[dl]){
			++dl;
			a[dl]=tmp;
		}
		top=nci;
		while(1){
			if(a[top]==-1){
				top++;
				continue;
			}
			tmp=cfs+a[top];
			if(tmp>n)return;
			if(tmp>a[dl]){
				++dl;
				a[dl]=tmp;
			}
			if(tmp>cfs*a[nci]-a[dl]){
				cfs*=a[nci];
				for(long long i=nci+1;i<=dl;i++){
					if(a[i]%a[nci]==0){
						a[i]=-1;
					}
				} 
				for(long long i=nci;a[i]==-1;++i,++nci);
				nci++;
				top=dl; 
				goto step1;
			}
			top++;
		}
		step1:
		top=dl; 
	}
}
void shuchu(){
	long long top=1;
	for(long long i=1;i<=dl;++i){
		if(a[i]!=-1){
			aa[top++]=a[i];
		}
	}
	top=1;
	for(long long i=nci;i<=dl;++i){
		for(long long j=i;aa[i]*aa[j]<=n;++j){
			if(aa[i]*aa[j]==0)goto out;
			hs[top]=aa[i]*aa[j];
			top++;
		}
	}
	out:
	sort(hs+1,hs+top);
	top=1;
	for(long long i=1;i<=dl;++i){
		if(aa[i]==0)return;
		for(;aa[i]>hs[top];top++);
		if(aa[i]!=hs[top])cout<<aa[i]<<' ';
	}
}
int main(){
	shuru();
	clac();
	shuchu();
	return 0;
}

算法证明

定义非正常合数。非正常合数指的是一个自然数n,用从2开始的连续质数相乘,当乘积大于n时,用用过的除了最后一个之外的质数去除n,如果都无法整除,但n却是个合数,这时,我们就称n是非正常合数。如49(2*3*5*7=210,49÷2=24余1,49÷2=24余1,49÷3=16余1,49÷5=9余4)91,121等
定义正常合数,就是不是非正常合数的合数。如4,6,10。
定义乘法式数:用2开始连续乘i个质数,si=2×3×……×pi
Pi是第i个质数。
    
要证明用我的算法是对的,就是不多不少的算出质数和非正常合数。
也就是要证明用我的算法算出的结果一定是质数或非正常合数,并且不会漏。
先证明我的算法算出的结果一定是质数或非正常合数。
也就是证明我的算法算出的结果一定不是正常合数。
我们先证明以下定理:
如果自然数n,用n的平方根及以下的质数去除它,都不整除,那么n是质数。                                    ①
只需证明①的逆否命题:
如果n是合数,那么用n的平方根及以下的质数去除它,存在一个质数能把它整除。                                ②
不妨设②中n=pq。(p、q是非1正整数)
则p和q中必有一数小于等于n的平方根。           ③
若p小于n的平方根,③成立。
若p等于n的平方根,③成立。
若p大于n的平方根,则q小于n的平方根,③成立。
不妨设p是小于等于n的平方根的那个数,设q也一样。
若p是质数,那么p是小于等于n的平方根的质数,②成立。
若p是合数,那么将p分解质因数后,分解出来的质数一定小于p,所以小于n的平方根,②成立。
因为p是非1正整数,所以p要么是质数,要么是合数。
现在,我们回忆一下余数定理:
1.	一个数a除以另一个数b,若有余数,则a不整除b
2.	(a除以b的余数+c除以b的余数)÷b的余数等于(a+c)÷b的余数
3.	(|a除以b的余数-c除以b的余数|)÷b的余数等于(|a-c|)÷b的余数
X+si=质数或非正常合数。(x>pi,x是质数或非正常合数)④
要证明④,先把si展开:
Si=2×3×5×……×pi
而x除以上面式子中任一质数都有余数。
有余数+没余数=有余数。
  ↓      ↓     ↓
   X      si      质数或非正常合数
si -X =质数或非正常合数
有余数-没余数=有余数。
  ↓      ↓     ↓
   si       X     质数或非正常合数
成功证明用我的算法算出的结果一定是质数或非正常合数

算法时间复杂度和空间复杂度

和欧拉筛法做对比:
(假设用c++ long long类型存储,筛1亿,计算机每秒运行约1亿次(不输出,根据时间复杂度和空间复杂度估计))
欧拉筛法:时间约1s,空间6103MB左右
我的算法:时间约0.36s,空间443MB左右
时间复杂度和空间复杂度的对比(时间复杂度和空间复杂度是程序估计内存消耗和时间消耗的手段)
欧拉:时间复杂度O(n)空间复杂度O(n)
我  :时间复杂度O(m + w×log 2 w)空间复杂度O(m + w)
m=n以下的质数个数
w=n以下非正常合数个数

算法优缺点

优点:速度快,内存省
缺点:代码长,不易编写、调试。
2022/1/29 21:38
加载中...