质数
质数筛:
暴力筛
代码:
1 bool check_prime(int n) 2 { 3 if(n==1) return 0; 4 for(int i=1;i<=n;i++) 5 if(n%i==0) return 1; 6 return 0; 7 }
六筛法
代码:
1 bool check_prime(int n) 2 { 3 if(n==1) return 0;//1既不是质数也不是合数 4 if(n==2||n==3) return 1;//2,3不是6两侧的数但他是质数 5 if(n%6!=1&&n%6!=5) return 0;//质数只能是6两侧 6 int x=sqrt(n);//筛到根号n 7 for(int i=5;i<=x;i++) 8 if(n/i==0||n/(i+2)==0) return 0;//如果他还有约数 9 return 1;//若没有约数 10 }
引理:算术基本定理——任何一个大于1的自然数N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积
所以只需要n无法被质数整除n即为质数
由于6两侧的数不是2和3的倍数所以不需要用2和3来筛
也不需要用6n+2,3,4来筛因为这些都是2和3的倍数,如果该数能被筛掉则改该数也能被2和3整除,不符合上述条件
线性筛 (也叫欧拉筛)
代码:
int primes[N], cnt; // primes[]存储所有素数 bool st[N]; // st[x]存储x是否被筛掉 void get_primes(int n) { for (int i = 2; i <= n; i ++ ) { if (!st[i]) primes[cnt ++ ] = i;//如果没有没有被筛掉就存入primes for (int j = 0; primes[j] <= n / i; j ++ ) { st[primes[j] * i] = true; if (i % primes[j] == 0) break; } } }
引理:算术基本定理——任何一个大于1的自然数N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积
显然,在所有大于0的自然数中,除了质数就是合数.要求质数,只需要”筛”去所有的合数即可.如何筛去合数
这里就应用到了算术基本定理.关于合数,这里我们需要注意两点:
(1).所有合数都要筛到
(2).不能有重复筛选,否则无法达到在线性时间内的运行了
要做到第一点,根据算术基本定理:n=q*m(q表示最小质数,m=N/q,显然m>=q),对N内的m和q进行枚举
这样我们就保证了能枚举N以内的所有整数,然而我们还不能保证枚举的合数不重复。
先来思考一下为什么会有重复,由于对于任意一个n=m*q,m和q是相对的两个状态,m大了q就变小,m小了q就变大。设n=m1*q1=m2*q2,q1<=q2<=m2<=m1我们这里需要保证当且仅当在q1是最小质因数时能求解,也就是去除q2和m2的情况.因为q1与q2互质,且q1<q2,则有m2%q1=0;由于每一个i值都是不同的因此我们认为当前的i值符合m1的条件因此临界条件为q1=q2,m2=m1,此时q1再增大时就有危险因为此时不符合除去q2和m2的条件。
①算法特性决定了找到的素数只能从自身开始乘。比如找到素数5时,它的2、3、4倍已经删不到了,这样避免了重复删。(虽然单独列出但也可以合并进②)
②if(i%p[j]==0)break;语句实现不重复删。证明很简单,自然数i从最小素数2开始乘,i×p[j]以每个p[j]为最小质因数,直到p[j]整除i时,i×p[j]还是以p[j]为最小质因数,但下一个数i×p[j+1]=(i/p[j])×p[j]×p[j+1]中p[j+1]就不是最小质因数了,所以不必继续乘了。
所以关键步骤来了: if(i%peimes[j]==0) break;
当i是primes[j]的倍数时直接跳出循环,设i=primes[j]*t,此时有i*primes[j+1]=primes[j]*t*primes[j+1]
可以看到此时的最小质数时primes[j],为了避免与当m=primes[j+1]*t时有重复,这里可以通过break跳过计算
此外还需注意:要保证m从2开始,因为1*q=1且i%1==0;
质因子:
试除法求质因子
1 void divide(int x) 2 { 3 for (int i = 2; i <= x / i; i ++ )//只用筛到根号x 4 if (x % i == 0) 5 { 6 int s = 0; 7 while (x % i == 0) x /= i, s ++ ; 8 printf("%d %d\n",i,s); 9 } 10 if (x > 1) printf("%d 1\n",x); 11 cout << endl; 12 }
分解质因数用短除法,把一个数进行短除可以分解成若干个质数相乘
分解质因数要从最小的质数2开始除,直到没有因数2再除以下一个质数3…直至除得的商也是质数为止。