线性筛法
维护一个质数表。
对于每个数a
,从小到大枚举所有质数b
,将a*b
打上标记。如果b|a
,停止枚举。
可以证明每个合数会被它的最小的质因子打上标记。
时间复杂度O(n)
拓展欧几里得
如何解方程ax+by=c
?
a,b,c
是常数,x,y
是变量,x1,y1
是方程的一组解
设a1=b
,b1=a%b
,a1*x1+b1*y1=c
b*x1+(a-[a/b]*b)*y1=c
a*y1+b*(x1-[a/b]*y1)=c
那么x=y1
,y=x1-[a/b]y1
时间复杂度O(logn)
Stein算法
辗转相除法求gcd(a,b)
时涉及除法和取模,常数太大了。
换成Stein算法吧!
a,b
为偶数,则gcd(a,b)=2*gcd(a/2,b/2)
a
为奇数,b
为偶数,则gcd(a,b)=gcd(a,b/2)
a,b
为奇数。假设a>=b
,则gcd(a,b)=gcd((a-b)/2,b)
a
为0,则返回b
用>>1
代替/2
的操作,用&1
代替%2
时间复杂度仍然是O(logn)
,但是除法和取模换成了位运算。
快速幂
如何求a^b mod p
?
b为偶数时,a^b ≡ (a^(b/2))^2
b为奇数时,a^b ≡ (a^⌊b/2⌋)^2*a
递归处理a^⌊b/2⌋
时间复杂度O(logb)
线性求逆元
给定质数p
,求出1至p-1
的逆元。
inv(i) ≡ -[p/i]*inv(p%i)
证明
i*[p/i]+p%i ≡ 0
-i*[p/i] ≡ p%i
i*(-[p/i]* inv(p%i)) ≡ 1
即inv(i)=-[p/i]*inv(p%i)
即inv[i]=(p-p/i)*inv[p%i]%p
快速求逆元
给定x和p,快速求出x在mod p意义下的逆元.
x*x^(-1) ≡ 1 (mod p)
x*x^(-1)=kp+1
x*x^(-1)+(-p)*k=1
使用拓展欧几里得求解。
拓展欧几里得太麻烦了,有没有更方便的做法?
①x*x^(φ(p)-1) ≡ 1 (mod p)
②inv(x)=x^(p-2)%p
费马小定理
若p
是质数,则ap-1 ≡ 1 (mod p)
{a,2a,…,(p-1)a}={1,2,…,p-1}
a* 2a* … * (p-1)a ≡ 1* 2 * … * (p-1)
ap-1*(p-1)! ≡ (p-1)!
ap-1 ≡ 1
欧拉定理
若(a,p)=1
,则aφ(p) ≡1 (mod p)
记φ(p)=n
,x1…xn
为1
至p-1
中与p
互质的数,{x1a,x2a,…,xna}={x1,x2,…,xn}
x1a* x2a* …* xna ≡ x1* x2* …*xn
an ≡ 1
中国剩余定理
解方程x ≡ai (mod pi)
,其中pi两两互质。
记qij
表示pi
在模pj
意义下的逆元。
x ≡ Σ(ai* π(pj * qji)) (mod p1 * p2 *…pn)
。
如果pi
不互质,将每个pi
拆分成质数的幂。
比如把a≡7 (mod 12)
,拆成a≡1 (mod 3)
和a≡3 (mod 4)
求欧拉函数
求出φ(1)
到φ(n)
。
记i= p1a1*… *pkak
φ(i)=i* (1-1/p1)* …* (1-1/pk)=p1a1-1* …* pkak-1* (p1-1)* …*(pk-1)
用线性筛求出每个数的最小质因数xi
。
若xi | i/xi
,则φ(i)=φ(i/xi)* xi
,否则φ(i)=φ(i/xi)* (xi-1)
。