数论专题学习笔记
数论分为三个部分
题目完成进度
3/5
一、质数
嘛质数的定义什么的应该算是小学数学内容啦?所以这里就不讲了,提一个结论就是:自然数中的质数不多,对于一个足够大的自然数N,不大于N的质数大约有lnN个。
判定单个质数方法
1.试除法
这是最简单的方法了,就是用这个数n去除以2~,除得尽就是合数,不然就是质数。
2.Miller-Rabin算法
这是一种随机的高效算法
这里要用到一个定理——费马小定理:
若p是质数,则对于任意整数x,有xp≡x(mod p)
若x与p互质,则有xp-1≡1(mod p)
由此可得,对于任意质数p,以及对于模p的剩余类环{1,2,3……,p-1}中任意的x,都满足xp≡x(mod p),即xp-1≡1(mod p),这样我们就可以排除大量的合数。
但是费马小定理中p是质数的条件只是充分条件,而非必要条件,也就是说,可能存在一个合数p,当x取到某一值时,xp≡x(mod p)也成立。
为了提高答案的正确率,我们要选取多个不同的x来进行判断,如果有一个x无法满足条件,那么p就一定不是质数。
但是依然存在特殊情况,有这样一类合数p,对于1~p-1的任意一个x,都满足xp≡x(mod p),那么这类合数称为Carmichael(卡曼克尔)数,比如561
因为这类数的存在,我们利用费马小定理无法准确判断一个数是合数还是质数。
于是我们要进行二次探测:
已知x²≡1(mod p),若p为质数,则有x≡1(mod p)或x≡p-1(mod p)
证明先咕着
由此我们就得到了Miller-Rabin算法,具体过程如下:
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) 来进行测试。
<1>如果测试后即不等于 1 也不等于 (p-1) ,则说明是合数,结束,否则继续。
<2>如果测试 x^((p-1)/2)=1 ( mod p )通过 , 则继续执行第 2 步,即看( p-1 ) /2 是否偶数,是的话,继续递归测试,只要有一环判断不通过,那么p就是合数;如果(p-1)/2是奇数,那么就直接判定p是合数。
<3>如果测试 x^((p-1)/2)=p-1 ( mod p )通过 ,说明到目前为止,没有条件能判定p不是质数,则此时默认p是质数。
代码也先咕着
如何求出1~n之间所有的质数
1.埃氏筛法
思想:对于任意一个质数x,2x,3x,4x……都不是质数
具体操作:从2开始,每次扫描到一个质数,就把它的倍数标记为合数,如此推进,当扫描到一个数没有被标记时,则意味着这个数p不能被2~p-1之内的数整除,所以p一定是质数。
改进:对于一个数x,小于x²的x的倍数已经在扫描比x小的数时被标记了,所以扫描到数x时,只需要标记比x²大的x的倍数即可。
void prime(int n){//求出1~n之间的所有质数 memset(v,0,sizeof(v));//1为合数,0为质数 for(int i=2;i<=n;i++){ if(v[i]==1) continue;//如果i是合数就不用管 cout<<i<<endl;//输出质数 for(int j=i;j<=n/i;j++) v[i*j]=1;//标记质数i的倍数 } return; }
这样做的时间复杂度为O(nlog(logn))
改进后的埃氏筛法任然会出现重复标记素数的情况,所以就有了接下来的线性筛法
2.线性筛法
思路:每个合数都用它的最小质因子把它筛掉。
void prim(int n){ int v[N],num=0;
memset(v,0,sizeof(v)); int prim[N]; go(i,2,n){ if(!v[i])v[i]=i,prim[++num]=i; go(j,1,num){ if(i*prim[j]>n||prim[j]>v[i])break; v[i*prim[j]]=prim[j]; } } return; }
分解质因数
首先是一个必须要知道的东西——算数基本定理:
任何一个大于一的整数都能唯一分解成有限个质数的乘积,可写作:N=p1c1p2c3……pmcm,其中ci都是正整数,pi都是质数,且满足p1<p2<……<pm
放个代码就溜啦QWQ
void divide(int n){ int p[MAX],c[MAX],m=0; for(int i=2;i<=sqrt(n);i++){ if(n%i==0){//此处i一定是质数 p[++m]=i;c[m]=1; n/=i; while(n%i==0){//把n中的i全部除尽 c[m]++; n/=i; } } } if(n>1) p[++m]=n;c[m]=1;//n本身可能是质数 return; }
来一道例题吧——
二、约数
定义也很简单,所以就不讲了,先讲一下算数基本定理的推论:
N的正约数集合可以写作{p1b1p2b2……pmbm},其中0≤bi≤ci
N的正约数个数为:(c1+1)*(c2+1)*……*(cm+1)=$\prod_{i=1}^{m} c_{i}+1$
N的所有正约数的和为:(1+p1+p12+……p1c1)*……*(1+pm+pm2+……+pmcm)=$\prod_{i=1}^{m} (\sum_{j=1}^{c_{i}}(p_{i})^{j})$
约数的求法
1.试除法
因为约数是成对出现的,所以只要扫描1~$\sqrt{n}$的每一个数判断即可
这样做的时间复杂度是O($\sqrt{n}$)
由此还可以得到一个推论:一个整数n的约数上限是$\sqrt{n}$
2.倍除法
思想:对于每个数d,1~n中以d为约数的就是d的倍数。
走一波代码——
vector <int> factor[MAX];//factor[i][j]表示数i的第j个约数 for(int i=1;i<=n;i++) for(int j=1;j<n/i;j++) factor[i*j].push_back(i);
其实……挺简单的哈QAQ
这个方法的时间复杂度为O(n/1+n/2+n/3+……+n/n)=O(nlogn)
于是我们又可以得到一个推论:1~n的每个数的约数总和约为nlogn
最大公约数
有一个简单的定理:对于任意自然数a,b都有:a*b=gcd(a,b)*lcm(a,b)
证明一下:
设d=gcd(a,b),a0=a/d,b0=b/d。
根据最大公约数的定义,可得gcd(a0,b0)=1;又由最小公倍数的定义可得,lcm(a0,b0)=a0*b0.
于是lcm(a,b)*gcd(a,b)=lcm(a0*d,b0*d)*d=lcm(a0,b0)*d*d=(a0*d)*(b0*d)=a*b
好这个东西后面不会讲到它了但是做题很有用所以一定要记住
嘛讲一下求最大公约数的方法吧
1.更相减损术
对于任意自然数a,b,且a≥b,都有gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)
对于任意自然数a,b,有gcd(2a,2b)=2*gcd(a,b)
2.欧几里得算法
对于任意自然数a,b,且b≠0,有:gcd(a,b)=gcd(a,a%b)
证明:
若a<b,则gcd(b,a%b)=gcd(b,a)=gcd(a,b)
若a≥b,设a=q*b+r,其中0≤r<b。显然r=a%b。对于a,b的任意公约数d,因为d|a,d|(q*b),故d|(a-q*b),即d|r
代码好短呀就一行
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
欧几里得算法求最大公约数的复杂度为min(O(loga),O(logb)),即O(logn)
互质与欧拉函数
互质的概念就不讲了,说一说欧拉函数的概念吧:[1,N]中与N互质的数的个数被称为欧拉函数,记为φ(N)
然后是几条非常重要的关于欧拉函数的性质
1.φ(1)=1
没错1与自己互质的,因为gcd(1,1)=1符合互质的定义
2.当p为质数时,φ(p)=p-1
因为质数的因数只有1和自己本身,所以在[1,p]的范围内和质数p互质的数就是出了p本身之外的p-1个数
3.当p为质数时,φ(pk)=pk-pk-1=pk(1-1/p)
哗我不记得证明过程了,还是先咕着
4.对于任意的n>1,[1,n]中与n互质的数的和为n*φ(n)/2
5.由算数基本定理可得,φ(n)=n*$\prod_{质数p|n}(1-1/p)$,这也是欧拉函数的计算公式
设p是n的质因子,则1~n中p的倍数有p,2p,……(n/p)*p,共n/p个。同理,q作为n的质因子,则1~n中q的倍数有n/q个。如果我们把这n/p+n/q个数去掉,那么p*q的倍数被排除了两次,需要加回来一次。因此,1~n中不与n含有共同质因子p或q的数的个数为:$n-\frac{n}{p}-\frac{n}{q}-\frac{n}{p*q}=n*(1-\frac{1}{p}-\frac{1}{q}-\frac{1}{p*q})=n(1-\frac{1}{p})(1-\frac{1}{q})$
6.若a,b互质,则有φ(a*b)=φ(a)*φ(b),即欧拉函数为积性函数
7.一个数n,等于它的约数的欧拉函数值之和,即n=$\sum_{d|n}d$
8.若p|n且p2|n,则有φ(n)=φ(n/p)*p
因为p|n且p2|n,所以n和n/p包含相同的质因子,按照计算公式算出φ(n)和φ(n/p)的值相除得商为p,得证
9.若质数p|n且p2$\not\mid$n,则φ(n)=φ(n/p)*(p-1)
因为p|n且p2$\not\mid$n,所以p与n/p互质,由性质6可得φ(n)=φ(n/p)*φ(p),而p是质数,所以可得φ(p)=p-1
综上,φ(n)=φ(n/p)*(p-1),得证
那么又要如何计算每个数的欧拉函数值呢?其实可以在分解质因子的过程中一并完成,详见代码
int Oula(int n){//求phi[n]的值 int ans=n; for(int i=2;i*i<=n;i++){//分解质因子 if(n%i==0){ ans=ans/i*(i-1);//性质5的公式变形,计算欧拉函数 while(n%i==0) n/=i; } } if(n>1) ans=ans/n*(n-1); return ans; }
这样的算法时间复杂度为O($\sqrt{n}$)
这里也放一道例题吧QWQ
三、同余
同余
1.同余
同余,顾名思义就是余数相同的意思
若整数a和整数b除以正整数m的余数相等,则称a,b模m同余,记为a≡b(mod m)
2.同余类
对于$\forall a\in[0,m-1]$,集合{a+km}($k\in Z$)中的所有数在模m的意义下与a同余,余数都是a,则该集合称为一个模m的同余类,记为$\overline{a}$
3.剩余系
模m的同余类共有m个,分别是$\overline{0},\overline{1},\overline{2},……,\overline{m-1}$,它们构成m的完全剩余系
1~m中与m互质的数代表的同余类有φ(m)个,它们构成m的简化剩余系
m的简化剩余系关于模m乘法封闭
差不多就这样,不过这里还有一个比较重要的东西就是欧拉定理:
若正整数a,n互质,则有aφ(n)≡1(mod n)
同时还有一个推论:
若正整数a,n互质,则对于任意的正整数b,都有ab≡ab%φ(n)(mod n)
这里放一个例题——(我还没有做完的例题QAQ)
The Luckiest Number(poj3696)
扩展欧几里得
1.贝祖定理
对于任意整数a,b,存在一对整数x,y,满足ax+by=gcd(a,b)
证明:
在算法的最后一步,即b=0时,显然可得x=1,y=0
若b>0,则gcd(a,b)=gcd(b,a%b)。假设此时存在一对整数x,y满足b*x+(a%b)*y=gcd(b,a%b),因为bx+(a%b)y=bx+(a-b*$\lfloor a/b \rfloor$)y=ay-b(x-$\lfloor a/b \rfloor$*y),所以我们可以令x1=y,y1=x-$\lfloor a/b \rfloor$*y,这样就得到了ax1+by1=gcd(a,b)
2.代码实现
int exgcd(int a,int b,int &x,int &y){//返回值为gcd(a,b) if(b==0) {x=1;y=0;return a;}//如果b=0,就到了最后一步 int d=exgcd(b,a%b,x,y);//递归调用 int z=x;x=y;y=z-y*(a/b); return d; }
3.扩展延伸
对于更加一般的方程ax+by=c,它有解当且仅当gcd(a,b)|c,我们可以先求出ax+by=gcd(a,b)的一组特解x0,y0,然后同时乘上c/gcd(a,b)
事实上,方程ax+by=c的通解可以表示为:$x=\frac{c}{gcd(a,b)}*x_{0}+k*\frac{b}{gcd(a,b)}$,$y=\frac{c}{gcd(a,b)}*y_{0}-k*\frac{a}{gcd(a,b)}$ ($k\in Z$)
乘法逆元
若整数b,m互质,并且b|a,则存在一个整数x,使得a/b≡a*x(mod m),称x为b的模m乘法逆元,记为b-1(mod m)
这里我不想写了,去看一下wch的blog吧QAQ
放一个例题,这是第四个例题了——
线性同余方程
给定整数a,b,m,求一个整数x满足a*x≡b(mod m),或者给出无解。因为未知数的指数为1,所以我们称之为一次同余方程,也称线性同余方程。
a*x≡b(mod m)等价于a*x-b是m的倍数,不妨设为-y倍。于是,该方程可以改写为a*x+m*y=b,于是这就和上面提到的方程十分类似了,所以可得x=x0*b/gcd(a,m)就是原线性同余方程的一个解。
方程的通解则是所有模(m/gcd(a,m))与x同余的整数
第五道例题——
这里再提一个东西叫做中国剩余定理,先放一放,把前面的落实完了再来学这个