基础数论入门

来源:互联网 发布:上海威利旺卡学费知乎 编辑:程序博客网 时间:2024/06/05 15:19

(一)定理和性质

一、裴蜀定理

如果 a,bN , (a,b)=d 那么一定存在 x,y 使得 d|(ax+by)
证明:非常简单,鉴于可能有数论刚入门的OIer所以这里简单证明一下:
因为(a,b)=d
所以我们就可以假设 a=pd , b=qd
那么ax+by=pdx+qdy=d(px+qy) 得证

二、整除的性质

a|c,b|c,(a,b)=1ab|c

a|bc,(a,b)=1a|c

p|abp|ap|b

正确性显然

三、同余

ab(mod m)m|(ab)

ab(mod m),ab(mod n)ab(mod [m,n])

(k,m)=d,kaka(mod m)aa(mod md)

第二个式子证明:
(ab)=xm=yn=k[m,n]

第三个式子证明:
k=qd,m=pd
kaka=cm
aa=cmk=cmqd=cqmd

四、逆元

如果(b,m)=1,那么存在b1 使得bb11(mod m)
P.S:这个-1次方只是表示逆元一个符号 并不是真的-1次方 但是可以把它当成-1次方在同余中进行运算

五、剩余系

任何m个分别属于m个剩余类的数组组成剩余系

六、φ

所有的n满足0nm,(n,m)=1 构成了一个模m的简化剩余系,简称缩系
记录这样的n的个数为φ(m)

七、关于缩系的一个定理

如果(m,m)=1,a取遍模m的缩系,a’取遍模m’的缩系,那么am+am 取遍模mm的缩系
证明自己yy一下好啦

八、欧拉定理

如果(a,m)=1,那么aφ(m)1(mod m)
证明:
当x取遍模m的缩系时,ax也取遍模m的缩系(这个自己yy一下,具体证明不太会说qwq)
所以我们可以得出xax(mod m)
axaφ(m)x
用处:如果(a,m)=1,abmod m可以转化成 ab mod φ(m)mod m
如果(a,m)1,abamin(b mod φ(m)+φ(m),b) mod m

九、拉格朗日定理

对于一个次数为n的多项式F(x),F(x)0(mod p)至多min(n,p)个解。

十、二次剩余

对于一个奇素数p,如果存在x使得x2a(mod p),那么称a为p的二次剩余。
如果ap121(mod p),那么a为p的二次剩余。
如果ap121(mod p),那么a为p的二次非剩余。

十一、威尔逊定理

(p1)!1(mod p)
证明:2到p-2这些数都存在逆元,可以两两匹配

十二、阶

如果(a,m)=1 那么记x为最小的正整数使得ax1(mod m)
结论:x|φ(m)
证明:反证法,设有一个最小的x , φ(m)=qx+r ,
aqx+r1(mod m)
ax1(mod m) 推出 ar1(mod m)
因为x是最小的满足条件的正整数 ,r<x ,所以r=0

十三、原根

如果g(mod m) 的阶为φ(m) 那么g为m的原根
g0,g1,,gφ(m)1 构成了模m的缩系。
只有1,2,4,pa,2pa存在原根。

十四、其他

φ(pe)=(p1)pe1
φ(m)=mp|m(11/p)(容斥原理求φ)

(二)算法

一、辗转相除法

直接贴代码吧,证明网上有详解,这里不再赘述

int gcd(int a,int b){    if (b==0) return a;    else return gcd(b,a%b); }

二、扩展欧几里得算法

用处:求解形如ax+by=gcd(a,b)的二元方程和线性同余方程
(axb(mod m) 等价于 ax+my=b)
推导:假设解出一组解(p,q)
pa+qb=gcd(a,b)
= gcd(b,a mod b)=pb+q(a mod b)=pb+q(a(ab)b)
= pb+qaq(ab)b=(pq(ab))b+qa
代码

int extended_gcd(int a,int b,int &x,int &y){    int ret,tmp;    if (!b)    {        x=1;y=0;return a;    }    ret=extended_gcd(b,a%b,x,y);    tmp=x;    x=y;    y=tmp-a/b*y;    return ret;}

一个神奇的小结论:
对方程ax+by=c,一组整数解为 (x0,y0)
则它的任意整数解可以写成 (x0+kb,y0ka) ,其中a=agcd(a,b)b=bgcd(a,b)
证明:
如果我们现在有解(x1,y1),任取另外一组解(x2,y2),则
ax1+by1=ax2+by2=gcd(a,b)
变形可以得到a(x1x2)=b(y2y1)
两边同时除以gcd(a,b)
得到a(x1x2)=b(y2y1)
因为(a,b)=1,所以 (x1x2) 一定是b’的倍数
x1x2=kb,得y2y1=ka

三、求逆元

由于aφ(m)1(mod m) 那么a1aφ(m)1(mod m)
如果m为素数,那么答案为am2
否则解线性同余方程

四、线性求1到n的逆元

f(i)=i! mod p,g(i)=i!1 mod p
g(i)=g(i+1)(i+1)
i1=f(i1)g(i)
算出fn然后求出fn的逆元gn,递推即可。

五、线性同余方程组(CRT)

形如xai(modmi)
解法:增量法
假设一开始的方程 xa1(mod p1),xa2(mod p2)
那么有 p1t+a1a2(mod p2)
p1ta2a1(mod p2)
p1t+p2y=a2a1
可以通过扩欧解出一个解t0
tt0(mod p2gcd(p2,p1)) (通过扩欧的小结论得出)
x0=p1t0+a1
xx0(mod lcm(p1,p2)) 满足左边等式的x都是这两个方程符合条件的解
然后加入下一个方程

六、求n!中p的指数

i1npi
还有一个O(1)求的公式(可以用于一些奇怪的数位dp)
nf(n)p1
f(n) 表示 n在p进制下的数位和
然而公式怎么推的并不会。。。

七、组合数

n,m较小的话 C(n,m)=C(n1,m)+C(n1,m1)递推即可(NOIP2017提高组DAY2T1!!!当时就因为不知道递推式吃了亏)
n,m较大的话暴力用f(n)g(m)g(nm)求就可以(f,g定义参考线性求1到n逆元里的定义)
还有一种更快的方式求组合数 想学习一下的人百度Lucas定理
这里给出公式:
C(n,m)%p=C(n%p,m%p)C(np,mp)%p

八、求阶

暴力枚举1到φ(m)判断即可

九、求原根

从小到大枚举g然后暴力判断即可

十、指数方程

axb(mod m)
如果m为素数:
使用BSGS(baby-step giant-step)解决
x=qtr ( t一般取根号下m上取整)
aqtbar(mod m)
从0-m 枚举r 算出bar 的值 填入一个哈希表中
从1-m 枚举q 算出aqt 的值,在哈希表中检索
如果m不是素数:
提取公因数直到gcd(a,m)=1
可能大家不理解
举个栗子:
假设我们要解一个方程8x16(mod 24)
8和24不互质
所以我们先提取一个8
变成 88x116(mod 24)
然后约一下变成 8x12(mod 3)
最后用BSGS求解得x=2
如果(a,m)(a,m,b)的话无解
xab(mod m)
如果m为素数:
如果gcd(a,φ(m))=1,那么求出a模φ(m)的逆元a1
xaa1xba1(mod m)
直接解x即可
否则:
先求出m的原根g
解出一个s符合 gsb(mod m)
假设 x=gt
那么 gatgs(mod m)
由原根的性质得到:ats(mod φ(m))
解出t即可
如果m不为素数:
分解m然后用CRT合并
当出现2^n时,因为它没有原根,所以说枚举答案即可

十一、二次剩余

形如 x2b(mod p)
判断一个数是不是另一个数的二次剩余,只需要计算bp12%p是否等于1即可
复杂度O(p)
还有一种O(log n)的算法叫做cipolla’s algorithm,然而我并不会这种算法,而且这种算法貌似非常冷门,只有维基百科上才能查到…
至于二次剩余的用处嘛…据说可以用来卡常数

十二、Miller-rabin

一个判断一个数是不是素数的算法
并不会写…直接背代码就好2333

十三、Pollard-rho

分解质因数
也不会写…也可以直接背代码QwQ

(三)数论函数

一、积性函数

对于gcd(a,b)=1,如果 f(ab)=f(a)f(b) 那么f(x) 为积性函数
常见的积性函数 d(x),σ(x),id(x),e(x),l(x),μ(x)
d(x)=a|x1
σ(x)=a|xa
id(x)=x
l(x)=1
e(x)=1(x=1)
e(x)=0(x1)

二、狄利克雷卷积

两个数论函数f(x),g(x),令h=fg
h(x)=a|xf(a)g(xa)
几条性质:
①卷积满足交换律,结合律。
②两个积性函数的卷积还是积性函数
fe=f

三、莫比乌斯函数

μ(n)=1k (k为n分解质因数后不同质因数的个数)
如果n有平方因子那么μ(n)=0
如何n=1那么μ(n)=1
μl=e
d|nμ(d)=e(n) (这个结论大家自己想一下,可以借助杨辉三角辅助理解)

四、莫比乌斯反演

如果F(n)=d|nf(d) 那么 f(n)=d|nμ(d)F(nd)
推导:
F=fl
Fμ=flμ=fe=f

五、线性筛素数

思想:每个合数只被它最小的素因子访问到
代码:

void get_prim(int n){    vis[1]=1;    for (int i=2;i<=n;i++)    {        if (!vis[i])        {            cnt++;prim[cnt]=i;        }        for (int j=1;j<=cnt&&i*prim[j]<=n;j++)        {            vis[i*prim[j]]=1;            if (i%prim[j]==0) break;  //看不懂这一步的去重新理解思想        }    }}

扩展:通过线性筛可以线性求出一个积性函数的值。

欢迎各位神犇前来交流qwq