谢秋锋 长沙市长郡中学 简单数论

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
mr(p) if(p == 2 || p == 3 || p == 7 || p == 61|| p == 24251 ) return true return mr0(2, p) && mr0(3, p) && mr0(5, p) && mr0(61, p) && mr0(24251, p)
mr0(x, p) if (x^(p-1)) % p != 1 return false k=p-1 while k % 2 == 0 k=k/2 t = x^k % p if(t != 1 && t != p - 1) return false if(t == p - 1) return true return true
简单数论
长沙市长郡中学
主讲:谢秋锋
信息学中的数学知识:

1、数论


2、线性代数
的 数
3、组合数学

4、概率论


5、博弈论
1、质数 2、约数 3、同余
01 质数
1 质数
定义:若一个大于1的正整数无法被除了1和它自身之外的任何自 然数整除,则称该数为质数(或素数),否则称该正整数为合数。 1既不是质数也不是合数
}
时间复杂度为:O(n+n/2+n/3+……+n/n)=O(nlogn)
倍除法的推论: 1~n每个数的约数个数பைடு நூலகம்总和大约为nlogn
3 最大公约数
定义:最大公约数:a与b约数最大的一个,记为gcd(a,b); 最小公倍数:a与b倍数最小的一个,记为lcm(a,b)。
所以:用筛法求出2~ R 之间的所有质数,对于每个质数p,把[L,R]中能被p整除的数标记
即标记i*p(

L p


i


R p

)为合数。
最终未被标记的为[L,R]中的质数,对相邻的质数两两比较,找出差最大的即可。
时间复杂度为(
RL
质数p R
) o( R log log P
R (R L) log log R)
02 约数
1 约数
定义:若整数n除以整数d的余数为0,即d能整除n,则称d是n的约数,n 是d的倍数,记为d|n。
算术基本定理的推论:
基本定理中正整数N被唯一分解为有限个质数的积: N=p1c1p2c2…pmcm 其中ci都是正整数,pi都是质数,且满足p1<p2<p3……<pm。
void divide(int n){ m=0; for (int i=2;i<=sqrt(n);i++){ if (n%i==0){//i是质数 p[++m]=i,c[m]=0; while (n % i == 0) n/=i,c[m]++;//除掉所有的i } } if (n>1) p[++m]=n,c[m]=1;//n是质数 for (int i=1;i<=m;i++)cout<<p[i]<<‘^’<<c[i]<<endl;
} } for (int i=1;i<=m;i++) cout<<factor[i]<<endl;
推论:一个整数n的约数个数上限为2
2 求1~N的正约数集合——倍数法
用“试除法”复杂度过高,为O( n ),反过来考虑,对于每个数d,1 ~n 中以d为 约数的数就是d的倍数d,2d,3d,…,⌊N/d⌋*d。
例:对Carmichael数561,进行Miller-Rabin测试:取x=2: 2^560=1(mod 561) 满足 2^280=1(mod 561) 满足 2^140=67(mod 561) 不满足 结论:561不是质数
2 单个质数判定——Miller-Robbin(高效的随机算法)
伪代码:
推论:N的正约数集合可写作: {p1b1p2b2…pmbm},其中0<=bi<=ci
N的正约数个数为:
m
(c1+1)*(c2+1)*……+(cm+1)= (ci 1)
i 1
N的所有正约数的和为: m ci (1+p1+p12+……+P1c1)*…*(1+pm+pm2+…+pmcm)= ( ( pi) j ) i1 j 0
vector<int>factor[500010]; for (int i=1;i<=n;i++)
for (int j=1;j<=n/i;j++) factor[i*j].push.back(i);
for (int i=1;i<=n;i++){ for (int j=0;j<factor[i].size();j++) printf(“%d ”,factor[i][j]); puts(“ ”);
m=0;//质数的数量
for(int i=2;i<=n;i++){
if (v[i]==0){ v[i]=i;prime[++m]=i;}//i是质数,质数的最小质因子就是自己
//给当前的数i乘上一个质因子
for (int j=1;j<=m;j++){
if(prime[j]>v[i]||prime[j]>n/i) break;
}
注:时间复杂度O( )
4 质因数分解
例题:Prime Distance (poj2689) 给定两个整数L,R(1<=L<=R<=231,R-L<=106),求闭区间[L,R]中相邻两个质数的差最大是多少, 输出这两个质数。
分析:L、R范围很大、任何已知算法都无法在规定时间内生成[1,R]中的所有质数 考虑R-L的值很小,且任何一个合数n必定包含一个不超过 的质因子。
3 质数的筛选——埃氏筛法(Eratosthenes)
问题:给定一个整数N,求出1~N之间的所有质数,称为质数的筛选问题。
埃氏筛法:思想:任意整数x的倍数2x,3x,…都不是质数。 具体操作:从2开始,从小到大扫描每个数x,把它的倍数2x,3x,…,⌊N/x⌋标为合数。 当扫描到一个数时,若它尚未被标记,则它不能被2~x-1之间的任何数整除,该数 就是质数。
具体:生成一个需要标记的合数时,每次向现有的数中乘上一个质因子,并且让它是这个合数的
最小质。这相当于让合数的质因子从大到小累积。例12的产生方式只有3*2*2。用最小质数2筛一次。
int v[MAX_N],prime[MAX_N];
void primes(int n){
memset(v,0,sizeof(v));//标记每个数的最小质因子,即i的最小质因子是v[i]
注:时间复杂度为O((log n)2)
快速幂:ab % c int power(int a, int b, int c) {
int res = 1; a %= c; while (b){ if (b & 1) res = (res * a) % c;
a = (a * a) % c; b >>= 1; } return res; }
试除法:结合质数判定的“试除法”和质数筛选的“埃氏筛法”,我们可以扫描2~⌊ ⌋ 的每个数d, 若d能整除N,则从N中除掉所有的因子d,同时累计除去的d的个数。 且这个能整除N的数一定是质数,因为一个合数的因子一定在扫描到这个合数之前就从N中除掉了。 特别的,若N没有被任何2~⌊ ⌋的数整除,则N是质数,无需分解。
Miller-Rabin(判断数p是否质数) 1、用数x对p做费马测试,即判断x^(p-1)模p的值,如果x^(p-1)=1(mod p),则说明通过费马测试; 继续做第2步,否则直接下结论p不是素数(通常选5个或更多已知的质数作为x)。 2、若p-1是偶数,那么可以继续通过x^((p-1)/2)是否等于1或(p-1)来进行测试。 a、如果测试后即不等于1也不等于(p-1),则说明是合数,结束,否则 b、如果测试x^((p-1)/2)=1(mod p)通过,则继续执行第2步,即看(p-1)/2是否偶数,是的话, 继续指数/2递归下去继续测试,只要一环判断不通过,那么就保证p是合数; c、如果测试x^((p-1)/2)=p-1(mod p)通过,说明到目前为止,没有某个数对p的测试可以否定p是 质数,而这种情况也没办法再套用二次探测定理继续探测,我们就默认p目前判断结果是质数。
v[i*prime[j]]=prime[j]; //prime[j]是合数i*prime[j]的最小质因子
}
}
for (int i=1;i<=m;i++)cout<<prime[i]<<endl;
注:时间复杂度O(N)
}
4 质因数分解
算术基本定理: 任何一个大于1的正整数都能唯一分解为有限个质数的乘积,可写作: N=p1c1p2c2…pmcm 其中ci都是正整数,pi都是质数,且满足p1<p2<p3……<pm。
2 求数n的正约数集合——试除法
约数成对出现,只需扫描d=1~ ,若d|n,则n/d也是n的约数。时间复杂度为O( )
int factor[1600],m=0; for (int i=1;i*i<=n;i++){
if (n % i==0){ factor[++m]=i; if (i != n/i) factor[++m]=n/i;
但是: 费马小定理中p是素数是xp=x(mod p)的充分条件,而非必要条件。 比如:56=5(mod 6),但我们不能说6是素数。
因此我们需要从模p的剩余类环中选取更多的数进行测试,以增强结果的可信度,只要存在一个数x不满足 xp=x(mod p),那么p就绝不可能是素数。但是还是存在一类极端的合数p,使得对于任意1,..,p-1中的x都满足 xp=x(mod p),这类合数称为Carmichael(卡曼克尔数)数,一个例子就是561。由于这类数的存在,使得我们用费 马小定理完全无法正确断定一个数为素数还是合数。
伪素数测试
2 单个质数判定——Miller-Rabin(高效的随机算法)
二次探测定理:若x2 ≡1(mod p) 若p为质数,则x≡1(mod p) 或 x≡p-1(mod p)
因为:若x^2=1(mod p),那么若p是素数,则(x-1)(x+1)=0(mod p); 除非p为2,否则(x-1)与(x+1)在模p的性质下是不相等的; 无论p是否为2,都可以保证有(x-1)=0(mod p)或者(x+1)=0(mod p)(因为模p剩余类环是整环), 即x=1或x=p-1。
}
注:时间复杂度O(NloglogN),非常接近于线性。
3 质数的筛选——线性筛法
改进后的埃氏筛法仍然有重复标记合数。 例如:12,即会被作为2的倍数标记,12=6*2,也会被作为3的标记,12=4*3;根本原因:没有唯一的产生12的方式。
线性筛:每个合数被它的最小质因子筛一次。
例:12的最小质因子为2,那么12只会被2标记一次即筛一次。
} 时间复杂度:
2 单个质数判定——Miller-Rabin(高效的随机算法)
费马小定理:若p为质数,则对于任意整数x,有xp≡x(mod p)。 若x与p互质,则xp-1≡1(mod p)。
例如:质数5,25(mod 5)=2 满足费马小定理 合数6,26(mod 6)=4 不满足费马小定理 对于任意素数p,以及对于模p的剩余类环{1,2,...,p-1}中的任意数x,都满足xp=x(mod p),即xp-1=1(mod p)。 因此我们可以用这个小小的技巧来排除大量的合数。
改进:小于x2的x的倍数在扫描小于x的数时就已经被标记过了。所以,对于每个数x,我们只需要从 x2开始,把x2,(x+1)*x,…,⌊N/x⌋*x标记为合数即可。
void primes(int n){ memset(v,0,sizeof(v));//合数标记 for(int i=2;i<=n;i++){ if (v[i])continue; cout<<i<<endl;//i是质数 for (int j=i;j<=n/i;j++) v[i*j]=1; }
自然数集合中,质数的数量不多,对于一个足够大的整数N,不超 过N的质数大约有N/lnN个,即每lnN个数中大约有1个质数。
2 单个质数判定——试除法
问题:判断正整数N是否质数
算法:扫描2~ 之间的所有整数,依次检查它们能否整除N,若都不能整除,则N是质数, 否则N是合数。
代码: bool is_prime(int n){ for (int i=2;i<=sqrt(n);i++) if (n % i == 0) return false; return true;
相关文档
最新文档