ACM 筛素数总结
ACM中数论基础知识的运用

数论初步:一,整除与因式分解:1,算术基本定理: n =a1^r1*a2^r2*a3^r3……2,求素数:(试除法,筛选法):素数测试费马小定理:若p为素数,则对于任意小于p的正整数a,有a(p-1)≡1(mod p)证明:用欧拉定理直接得出二次探测定理:若p为素数,a2≡1(mod p)小于p的正整数解只有1和p-1满足费马小定理和二次探测定理的数可以确定是素数Miller-Rabin算法算法步骤:判定n是否为素数令n-1=m*2j,m为奇数随机在2到(n-1)之间取一个整数b令v=bm,之后每次对v平方,当v=1时,若上一次的v既不是1也不是(n-1),由二次探测定理,n不是素数,退出;不断循环直到计算出b(n-1)v=1,满足费马小定理,通过测试;否则n一定不是素数 选取几个不同的b多次测试Miller-Rabin只能算一种测试,因为通过测试的数不一定是素数,非素数通过测试的概率是1/4虽然一次测试的结果不一定令人满意,但五六次随机测试基本可以保证正确率超过99.9%For (int i = 2; i < n ;i++){For (int j = 2,flay = 1; j < sqrt (n); j++)If (I % j == 0){Printf (“i不是素数”);flay = 0;}Printf (“I是素数”);}3 ,int m = sqrt (n+0.5);int c = 0;memset (vis,0,sizeof (vis));for (int i = 2; i < = m; i++)if (!vis[i]){prime[c++] = i;for (int j = i*i; j <= n; j+= i) vis[j] = 1;}4,int isprime[N];int cnt;int isok (int x){for(int i = 0; i < cnt && isprime[i] * isprime[i] <= x; i++)if (x % isprime[i] == 0) return 0;return 1;}void getprime (){isprime[0] = 2;isprime[1] = 3;cnt = 2;for (int i = 5; i < maxn; i++)if (isok (i))isprime[cnt++] = i;}5,因式分解:int Factor (int num){int m = 0;for (int i = 0; i < cnt && isprime[i]*isprime[i] <= num; i++){if (num%isprime[i] == 0){arr[++m] = isprime[i];r[m] = 0;while (num % isprime[i] == 0 && num){r[m]++;num/= isprime[i];}}}if (num > 1){arr[++m] = num;r[m] = 1;}return m;}6,求约数:void dfs (int now,int q,int m,int a,int b){if (flay) return ;if (q > a) return ;if (now == m+1){q 就是约数…..return ;}for (int i = 0,t = 1;i <= r[now];i++,t*=arr[now]){dfs (now+1,q*t,m,a,b);}}例题分析:Fzu上的题:()求一个数的真因子个数(不包括本身)。
素数(超详细!!!)

素数(超详细)整数惟⼀分解定理素数筛法给定n,求出1~n之间所有的质数。
⼀、Eratosthenes筛法(☒此处本应有⼀幅动图,然鹅我并不知道该如何显⽰动图(。-ω-)-ω-)-ω-)Eratosthenes筛法思想⼆、欧拉筛法(线性筛)埃⽒筛法中以n=30为例,30这个数被筛了3次,分别是:2*15(p=2)3*10(p=3)5*6(p=5)枚举 2~n 中的每⼀个数 i:如果 i 是素数则保存到素数表中;利⽤ i 和素数表中的素数 prime[j] 去筛除 i*prime[j] ,为了确保i*prime[j] 只被素数 prime[j] 筛除过这⼀次,要确保 prime[j] 是i*prime[j] 中最⼩的素还要⼩的素因⼦。
因⼦,即 i 中不能有⽐ prime[j] 还要⼩的素因⼦写法⼀:(仅⽤于判断)写法⼆:(可求出每个数的最⼩质因⼦)素数筛法优化素因数分解只要在判定素数时记录下每个数值的最⼩素因数即可。
⼀道肥肠简单的模板题——【例 1】Prime Distance(信息学奥赛⼀本通 1619)【题⽬描述】给定两个整数 L,R,求闭区间 [L,R] 中相邻两个质数差值最⼩的数对与差值最⼤的数对。
当存在多个时,输出靠前的素数对。
【输⼊】多组数据。
每⾏两个数 L,R。
【输出】详见输出样例。
【输⼊样例】2 1714 17【输出样例】2,3 are closest, 7,11 are most distant.There are no adjacent primes.。
c语言求素数最快方法

c语言求素数最快方法摘要:1.引言2.最快方法:埃拉托斯特尼筛法(Sieve of Eratosthenes)3.算法原理4.C语言实现5.代码解析6.性能测试与优化7.结论正文:**引言**在计算机科学和编程领域,寻找素数是一种常见的任务。
素数是指大于1的自然数中,除了1和它本身以外,不能被其他自然数整除的数。
求解素数问题有助于理解数论、密码学等领域。
本文将介绍求解素数的最快方法——埃拉托斯特尼筛法(Sieve of Eratosthenes)及其C语言实现。
**最快方法:埃拉托斯特尼筛法(Sieve of Eratosthenes)**埃拉托斯特尼筛法是一种基于二维数组的算法,用于找出小于等于上限的素数。
该算法利用了素数的性质:如果一个数是素数,那么它的平方模小于等于上限的数也是素数。
通过不断标记数组中的素数,最终得到小于等于上限的素数。
**算法原理**1.创建一个二维数组,用于存储小于等于上限的数。
2.初始化数组中的所有元素为1,表示都是素数。
3.从2开始,遍历数组,将数组中的所有素数两两相乘,得到的结果大于上限的,将其对应的元素标记为0,表示该数不是素数。
4.重复步骤3,直到数组中的所有元素都被标记或遍历到上限。
**C语言实现**以下是一个简单的C语言实现:```c#include <stdio.h>#include <stdbool.h>void sieve_of_eratosthenes(int limit) {bool *prime = (bool *)malloc((limit + 1) * sizeof(bool));for (int i = 0; i <= limit; i++) {prime[i] = true;}for (int p = 2; p * p <= limit; p++) {if (prime[p]) {for (int i = p * p; i <= limit; i += p) {prime[i] = false;}}}for (int i = 2; i <= limit; i++) {if (prime[i]) {printf("%d ", i);}}free(prime);}int main() {int limit;printf("请输入一个上限:");scanf("%d", &limit);sieve_of_eratosthenes(limit);return 0;}```**代码解析**1.首先,我们需要一个布尔数组来存储小于等于上限的数是否为素数。
acm算法经典例题

一、数论1: Wolf and Rabbit描述There is a hill with n holes around. The holes are signed from 0 to n-1.A rabbit must hide in one of the holes. A wolf searches the rabbit in anticlockwise order. The first hole he get into is the one signed with 0. Then he will get into the hole every m holes. For example, m=2 and n=6, the wolf will get into the holes which are signed 0,2,4,0. If the rabbit hides in the hole which signed 1,3 or 5, she will survive. So we call these holes the safe holes.输入The input starts with a positive integer P which indicates the number of test cases. Then on the following P lines,each line consists 2 positive integer m and n(0<m,n<2147483648).输出For each input m n, if safe holes exist, you should output "YES", else output "NO" in a single line.样例输入21 22 2样例输出NOYES翻译:描述一座山有n个洞,洞被标记为从0到n-1。
有关素数判断的一些算法(总结对比)

有关素数判断的⼀些算法(总结对⽐)素性测试是数论题中⽐较常⽤的⼀个技巧。
它可以很基础,也可以很⾼级(哲学)。
这次主要要介绍⼀下有关素数判断的奇技淫巧素数的判断主要分为两种:范围筛选型&&单个判断型我们先从范围筛选型这种常⽤的开始讲起,这⾥采⽤模板题来进⾏测试1.埃⽒筛这是最常⽤的筛法了,思路也很简单:任何⼀个素数的倍数都是合数然后我们O(n)扫⼀遍,同时筛去素数的倍数但是有⼀些数如6,会被2和3都筛去⼀次,就造成了效率上的浪费,所以复杂度经证明为**O(n log log n)CODE#include<cstdio>using namespace std;const int N=10000005;bool vis[N];int n,m,x;inline char tc(void){static char fl[100000],*A=fl,*B=fl;return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;}inline void read(int &x){x=0; char ch=tc();while (ch<'0'||ch>'9') ch=tc();while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();}inline void get_prime(int m){register int i,j;for (vis[1]=1,i=2;i<=m;++i)if (!vis[i]) for (j=i<<1;j<=m;j+=i) vis[j]=1;}int main(){//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);read(n); read(m); get_prime(n);while (m--){read(x);puts(vis[x]?"No":"Yes");}return 0;}2.线性筛(欧拉筛)这其实是对上者的优化,我们意识到⼀个数应该只有它的最⼩质因数删去,所以我们可以⼀边筛数的同时⼀边记录素数,这就是真正的O(n)复杂度CODE#include<cstdio>using namespace std;const int N=10000005;int prime[N],n,m,x,cnt;bool vis[N];inline char tc(void){static char fl[100000],*A=fl,*B=fl;return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;}inline void read(int &x){x=0; char ch=tc();while (ch<'0'||ch>'9') ch=tc();while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();}inline void Euler(int n){register int i,j;for (vis[1]=1,i=2;i<=n;++i){if (!vis[i]) prime[++cnt]=i;for (j=1;j<=cnt&&i*prime[j]<=n;++j){vis[i*prime[j]]=1;if (!(i%prime[j])) break;}}int main(){//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);read(n); read(m);Euler(n);while (m--){read(x);puts(vis[x]?"No":"Yes");}return 0;}注意上⾯的那句话:if (!(i%prime[j])) break;这保证了线性筛的效率,不会产⽣重复,因为当i%prime[j]==0时这个数就是让后⾯的数删去。
ACM数论01-素数(质数)的判断

ACM数论01-素数(质数)的判断⽤代码判断素数(质数)素数,⼜名质数。
它的定义很简单:在⼤于1的⾃然数中,只有1和它本⾝两个因⼦的数,就是素数(质数)。
注:本⼈喜欢⽤质数这个名字,所以下⽂中都⽤质数代表素数质数的名字叫prime number,所以在代码中,我们对质数总是使⽤prime进⾏变量的命名,对质数判断的函数也会变成isprime()(是质数吗?)或者⼲脆⽤简写isp()根据定义,我们可以很轻松的写出判断⼀个质数的代码:(c++):bool isp(int n){for(int i = 2; i < n; i++){if(n % i == 0) return false;}return true;}(java):static boolean isp(int n){for(int i = 2; i < n; i++){if(n % i == 0) return false;}return true;}这⾥默认不考虑1到底是不是质数,因为1本⾝就不存在质数的定义中。
这样写是可以判断是否是质数的,但如果你了解过时间复杂度,你就会喊出:我的⽼天爷啊!这也太慢了!判断⼀个质数的时间复杂度⾼达了:O(N)如何更加快速地判断⼀个数是否是质数?这⾥我们要引⼊⼀个显⽽易见的论据。
如果⼀个数n能被d整除(或者说d整除n),那么n也⼀定能被n/d整除我们⽤数学符号表⽰:d|n⇒n d|n|是整除符号,表⽰右边的数可以被左边的数整除我们举个例⼦理解吧:3|18⇒183|183可以整除18,18/3也可以整除18,这是显⽽易见的。
因为如果存在⼀个⼤于1的⾃然数,它就⼀定能写成如下的形式:N=A∗B哪怕是质数,也可以写成1*本⾝的形式,如果它是个合数,那么A和B必定不是1和本⾝。
那么从这个显⽽易见的结论,我们可以推出另⼀个结论:⼀个⼤于1的合数,它的因⼦除了1和本⾝以外,总是成对出现的,不过这⼀对可能是⼀样的数,⽐如36=6*6。
素数快速筛法及公式
素数快速筛法及公式素数快速筛法及公式梅生林安徽合肥2012.07.12摘要:在素数的研究中,总结出素数快速筛法及公式,在这个基础上扩展了素数的一些关系、性质。
关键词:素数快速筛法,素数通式,质数筛法公式1.引言素数(Prime Number)是指自然数中那些只能被1和本身整除的数,依次为2、3、5、7、11、13、17、19、23、29…。
前人已证明:素数有无限多个。
一直到现在人们判定、寻找素数的方法,还是古希腊的数学家艾拉托斯芬(Eratosthenes)提出过的筛式方法,简称“艾氏筛法”。
即在任意有限自然数N以内判定素数时,先把N一个不漏的写下来,然后划掉根号N()内所有素数的倍数,我们就能得到N以内的全部素数。
艾氏筛法判定素数的过程机械,也未能表示素数公式和一些性质。
关于寻找判定表示素数的方法公式,以前众多数学家进行了艰辛探索,也提出了很多关于素数的猜想和问题。
欧拉(Euler)就提出二项式公式n2-n+41能生成一部分素数的数型公式,直到现在,素数研究中仍然还有许多未解问题。
本文通过素数快速筛法及公式,总结出一些素数的新理论,使素数筛法及公式等都将是一次质变,将为素数研究抛砖引玉,也可能为数论增添上新的一页。
2.素数的快速筛法原理及公式当我们用艾氏筛法是要划掉每个合数,只2的倍数就差不多要划掉一半自然数,越往后面合数越多,而留下的素数越少。
我们能不能利用数学原理、公式去掉大部分合数呢?答案是肯定的。
2.1 当我们想去掉第一个素数2的倍数时,我们可能会想到用:2N+1 (N≥1)N为大于等于1的自然数,以下公式同上。
2.2 去掉2、3的倍数时,用2*3的倍数加上同为2、3互质的数:6N±12.3 去掉2、3、5的倍数时,用2*3*5的倍数加上同为2、3、5互质的数:30N±1,30N±7,30N±11,30N±13,2.4 去掉2、3、5、7的倍数时,同上的方法:210N±1,210N±11,210N±13,210N±17,210N±19,210N±23,210N±29,210N±31,210N±37,210N±41,210N±43,210N±47,210N±53,210N±59,210N±61,210N±67,210N±71,210N±73,210N±79,210N±83,210N±89,210N±97,210N±101,210N±103,2.5 去掉2、3、5、7、11的倍数时,同上的方法:2310N±1,2310N±13,2310N±17,2310N±19,……2310N±1139,2310N±1147,2310N±1151,2310N±1153,我们可以一直做下去,就会去掉从前面开始的素数倍数,划掉的合数比例将越来越少。
ACM中的数学问题March总结
欧几里德算法
• 欧几里德算法 (The Euclidean Algorithm) • 又称辗转相除法 或者 短除法 • 原理: gcd(a,b) = gcd(b,a mod b) • 证明: • 利用整除性质5(a=kb±c => a,b的公因数与b,c的公因数完全相同) • 辗转相除直到两数整除,其中的除数就是要求的最大公约数。
第16页/共96页
请写出12,10共有的倍 数
第17页/共96页
请写出12,10共有的倍 数
60,
第18页/共96页
请写出12,10共有的倍 数
60, 120,
第19页/共96页
请写出12,10共有的倍 数
60, 120, 180,
第20页/共96页
请写出12,10共有的倍 数
60, 120, 180, 240…
第7页/共96页
整除的基本性质
• 性质1: • a|b,b|c => a|c
• 性质2 : • a|b => a|bc
• 性质3 : • a|b,a|c => a|kb±lc
• 性质4 : • a|b,b|a => a=±b
第8页/共96页
整除的基本性质
• 性质5 : • a=kb±c => a,b的公因数与b,c的公因数完全相同 • 证明: • 假设d是b,c的公因数,即d|b, d|c。 • 利用整除性质3,d整除b,c的线性组合,故d|a。 • 所以d是a,b的公因数 • 反之,如果d是a,b的公因数,也能证出d是b,c的公因数
第34页/共96页
扩展欧几里德算法
• 扩展欧几里德算法(递归实现):
第35页/共96页
扩展欧几里德算法
03_ACM数论问题
伪素数
湖南工业大学
伪素数的一个用途 利用伪素数表来判定一个奇数n是否为素数。 如果n不能整除2^(n-1)-1,则据费马小定理知,n必为合数; 如果n能整除2^(n-1)-1 ,且n在伪素数表中,则n为合数,否则 为素数。 这种方法的关键就在于按伪素数表去掉伪素数,而这要求伪素数 在能整除2^(n-1)-1的数中相当少才行,这就是当n整除2^(n-1) -1时,n是合数的比例问题。 在前10亿个自然数中,共有50847534个素数,而只有以2为底的 伪素数5597个,即在此范围内n整除2n-1-1产生合数的可能性只 有0.011%。在10亿之内,n整除2^(n-1)-1同时整除3^(n-1)-1 的合数n只有1272个,即此时产生合数的可能性只有0.0025%。
思考: 递归的形式如何写?
工大ACM团队
扩展的欧几里德算法
湖南工业大学
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约 数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。如果gcd(a, b) =d,那么一定存在x,y满足ax+by=d。 扩展欧几里得算法其实是解二元一次不定方程的算法, Function extended_gcd(a,b:longint; Var x,y:longint):longint; Begin if b=0 then begin extended_gcd:=a; x:=1; y:=0; end else begin extended_gcd:=extended_gcd(b, a mod b); t:=x; x:=y; y:=t-(a div b) * y; end; End;
工大ACM团队
素数算法
一篇不大正经的有关素数的小结
⼀篇不⼤正经的有关素数的⼩结素数:也称质数、不可约数,不存在⾮平凡因⼦。
平凡因⼦:即对于任意数n都⾄少存在两个因⼦,⼀个是1,另⼀个是n本⾝,我们就叫它俩为n的平凡因⼦,其他的,都为n的不平凡因⼦。
性质:设π(n)为不超过n的质数个数那么,π(n)∽nln n(n越⼤,估计的越准确)质因数分解:Code:inline int factorize(int x,int p[]) {int cnt=0;for(int i=2; i*i<=x; ++i) {if(x%i==0) {p[cnt++]=i;x/=i;}}if(x>1) p[cnt++]=x;return cnt;}例题:质数有⽆限个,如何证明?反证法:假设质数是有限的∵假设为p1,p2,⋯p n∴M=p1∗p2∗⋯p n+1⼜∴M mod p1=1M mod p2=1⋯M mod p n=1∴M mod任何质数都是1,M不是任何质数的倍数,M是质数,与假设冲突,所以质数有⽆限个这样⼀想,求它是不是就有很多种⽅法啦~(Emma,19260817是个质数)1.⼀个毒瘤的判断素数法⼦(跑的贼快的那种,时间复杂度O(√n/3)):⾸先看⼀个关于质数分布的规律:≥5的质数⼀定和6的倍数相邻。
证明:令x≥1,将≥5的⾃然数表⽰如下:⋯6x−1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1⋯可以看到,不和6的倍数相邻的数为6x+2,6x+3,6x+4,由于2(3x+1),3(2x+1),2(3x+2),所以它们⼀定不是素数,再除去6x本⾝,显然,素数要出现只可这种⽅法裁剪了不和6的倍数相邻的数,虽然都没有降低时间复杂度的阶数,但都⼀定程度上加快了判断的速度。
inline int prime(int n) {if(n==1) return false;if(n==2 || n==3) return true;if(n%6!=1 && n%6!=5) return false;for(register int i=5; i<=sqrt(n); i+=6)if(n%i==0 || n%(i+2)==0) return false;return true;}2.⾮常朴素的⼀种算法(判断有没有能整除的数)#include<bits/stdc++.h>using namespace std;int main() {int n;cin>>n;for(int i=2; i<=n; i++) {if(n%i==0) {cout<<"flase";return 0;} else {cout<<"true";return 0;}}}3.⽹络上流传的素数打表:/*遇到素数需要打表时,先估算素数的个数:num = n / lnx;num为⼤概数字,越⼤误差越⼩(只是估计,⽤于估算素数表数组⼤⼩)这个打表法效率貌似很⾼,⽹上说⼏乎达到了线性时间(不知道是真是假=。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
【总结】关于求素数的说【两种筛法】
(学习小结,请无视)
素数大家都很熟了,不多说了,这里只想说一下求素数。
当然先是唯一素因子分解定理:合数a仅能以一种方式,写成如下的乘积形式:a=p1e1p2e2…prer
其中pi为素数,p1<p2<…<pr,且ei为正整数
对于一个整数n,当其在小于sqrt(n)范围里有一个约数,那么必然在大于sqrt(n)的范围里有对应的另一个Eratosthenes(埃拉托斯特尼筛法)都是到sqrt(n)的范围。
①。
试除法判素数
对于大于1的正整数a,如果a具有小于或等于sqrt(a)的素因子,则a为合数,否则a为素数。
因此,可用区间[2,sqrt(a)]内的数去试除a,只要有一个数能整除a ,则a为合数,否则a为素数。
这种判断素复杂度O(sqrt(n)).
IsPrime(a)
for(i=2;i*i<=a;i++)
if(a%i==0)
return a为合数
return a为素数
②。
Sieve Of Eratosthenes(埃拉托斯特尼筛法)
可以筛出2~n 范围里的所有素数。
1)将所有候选数2~n放入筛中;
2)找出筛中最小数P,P一定为素数。
3)宣布P为素数,并将P的所有倍数从筛中筛去;
4)重复2)至3)直到筛空.
其实,当P>sqrt(n)时筛中剩下的数就已经都是素数了。
//用数组prime[MAXN]记录是否为素数;
//prime[i]为0表示i为素数,否则为合数
int prime[MAXN]={0};
for(i=2;i*i<=n;i++)
{
if(prime[i]==0)
{
for(j=i+i;j<=n;j+=i)
prime[j]=1;
}
}
③。
线性筛法
对于Sieve Of Eratosthenes,普通的筛法如果是一个合数,那么会被多次筛掉,比如6,当2作为素数时筛掉一线性筛法保证所有合数只被筛掉一次
具体详见《ftfish利用积性函数的优化》,讲到了积性函数(对于正整数n的一个算术函数f(n),当中f(1)=1且称它为积性函数。
)
for(int i = 2; i < maxn; i ++){
if (!fg[i]) prim[np++] = i; //如果没被筛掉,那么就是素数
for(int j = 0; j < np && i*prim[j] < maxn; j ++){
//注意i不是素数的时候也筛
fg[i*prim[j]] = 1;
if (i % prim[j] == 0)break;
//这一步保证了筛法是线性的,这是整个算法的关键
}
}
摘:
利用了每个合数必有一个最小素因子。
每个合数仅被它的最小素因子筛去正好一次。
所以为线性时间。
代码中体现在:
if(i%prime[j]==0)break;
prime数组中的素数是递增的,当i 能整除prime[j],那么i*prime[j+1] 这个合数肯定被prime[j] 乘以某个数筛因为i中含有prime[j], prime[j] 比prime[j+1] 小。
接下去的素数同理。
所以不用筛下去了。
在满足i%pr[j]==0这个条件之前以及第一次满足改条件时,pr[j]必定是pr[j]*i的最小因子。