数论专题学习笔记

写在前面

数论分为三个部分

1.质数

2.约数

3.同余

 题目完成进度

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;
}

来一道例题吧——

Prime Distance (poj2689)

go back


 

二、约数

 定义也很简单,所以就不讲了,先讲一下算数基本定理的推论

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$ otmid$n,则φ(n)=φ(n/p)*(p-1)

因为p|n且p2$ otmid$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

Luogu P2158 仪仗队

go back


三、同余

同余

1.同余

同余,顾名思义就是余数相同的意思

若整数a和整数b除以正整数m的余数相等,则称a,b模m同余,记为a≡b(mod m)

2.同余类

对于$forall ain[0,m-1]$,集合{a+km}($kin 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 floor$)y=ay-b(x-$lfloor a/b floor$*y),所以我们可以令x1=y,y1=x-$lfloor a/b floor$*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)}$  ($kin Z$)

乘法逆元

若整数b,m互质,并且b|a,则存在一个整数x,使得a/b≡a*x(mod m),称x为b的模m乘法逆元,记为b-1(mod m)

这里我不想写了,去看一下wch的blog吧QAQ

放一个例题,这是第四个例题了——

Sumdiv(poj1845)

线性同余方程

给定整数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同余的整数

第五道例题——

同余方程(NOIP2012)

这里再提一个东西叫做中国剩余定理,先放一放,把前面的落实完了再来学这个

go back

原文地址:https://www.cnblogs.com/THWZF/p/10457243.html