唯一分解定理
n=i∏piαiνp(i)(n)=αi
素数
Fermat 素性检验:检验 an−1≡1(modn)。
二次探测定理:检验 x2≡1(modn)⟹x≡1(modn)∨x≡n−1(modn)。
上述检验若失败则说明 n 必不是质数。
Miller Rabin
分解 Fermat 素性检验中的指数,n−1=u×2t。
对于一个底数 a,求出 v=au(modn)。进行至多 t 次 v←v2 过程中进行二次探测。
通过所有二次探测后进行 Fermat 素性检验。
Miller Rabin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| inline ll qmul(ll a,ll b,ll m) { return (ull(a)*b-ull(ld(a)/m*b)*m+m)%m; } inline ll qpow(ll x,ll y,ll m) { ll r=1; for(;y;x=qmul(x,x,m),y/=2)if(y&1)r=qmul(r,x,m); return r; } constexpr ll A[7]={2,325,9375,28178,450775,9780504,1795265022};
inline bool MillerRabin(ll n) { if(n<3||n%2==0)return n==2; if(n%3==0)return n==3; ll u=n-1,t=0; while(u%2==0)u/=2,t++; for(int i=0;i<7;i++) { ll v=qpow(A[i]%n,u,n); if(v==0||v==1)continue; int s=0; for(;s<t;s++) { if(v==n-1)break; v=qmul(v,v,n); } if(s==t)return false; } return true; }
|
筛
埃氏筛
1 2 3 4 5 6 7 8
| std::vector<int> p; std::bitset<V> np; for(int i=2;i<=n;i++)if(!np[i]) { p.push_back(i); if(1ll*i*i>n)continue; for(int j=i*i;j<=n;j+=i)np[j]=true; }
|
线性筛
1 2 3 4 5 6 7 8 9 10 11 12
| std::vector<int> p; std::bitset<A> np; for(int i=2;i<=n;i++) { if(!np[i])p.push_back(i); for(int j:p) { if(1ll*i*j>n)break; np[i*j]=true; if(i%j==0)break; } }
|
爱用哪个用哪个。级别在 108 以下时埃氏筛可能有常数优势,109 时线性筛更快。
欧几里得算法
若 p=kq+r,则 r=pmodq,k=⌊p/q⌋。
设 a>b,g=gcd(a,b),则 g∣a,g∣b,即 g∣(a−kb),g∣amodb。
可得 gcd(a,b)=gcd(b,a−b)=gcd(b,amodb)。
1
| template<typename T> inline T gcd(T a,T b){return b?gcd(b,a%b):a;}
|
裴蜀定理
∃x,y∈Z,ax+by=gcd(a,b)。
显然可以在欧几里得算法过程中构造。
设 a=kb+r,gcd(a,b)=bx+ry,则 gcd(a,b)=bx+(a−kb)y=ay+(x−ky)b。
即 x′=y,y′=x−ky。
exCRT
为了求解线性同余方程 ax≡b(modm),通过 exgcd 求解 gcd(a,m)=ax′+my′。
可得
agcd(a,m)x′b+mgcd(a,m)y′b=b
这样我们就解出了一个特解。发现若 x0 是一个解,那么 x0+kgcd(a,m)m 也是一个解。
agcd(a,m)x′b+km+mgcd(a,m)y′b−ka=b
即 x≡x0(modm/gcd(a,m))。
那么对于方程组
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧a1x≡b1(modm1)a2x≡b2(modm2)⋮anx≡bn(modmn)
解得
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧x≡x1(modm1′)x≡x2(modm2′)⋮x≡xn(modmn′)
然后每次合并两个方程。设 x=x1+m1′y1=x2+m2′y2,可得 m1′y1=x2−x1+m2′y2≡x2−x1(modm2′)。解得 y1≡y0(modm2′/gcd(m1′,m2′))。代回有 x=x1+m1′y1≡x1+m1′y0(modm1′m2′/gcd(m1′,m2′)=lcm(m1′,m2′))。
CRT
数论分块
数论函数
常见完全积性函数:
- 元函数 ε(n)=[n=1]
- 单位函数 idk(n)=nk,恒等函数 I(n)=id0(n)=1
常见积性函数:
- 莫比乌斯函数 μ(n)=I−1
- 约数函数 σk(n)=∑d∣ndk,d(n)=σ0
- 欧拉函数 φ(n)=∑i=1n[i⊥n]
积性分解
f(n)=i∏f(piνp(i)(n))
积性函数取值只与素数幂次处取值有关。
Dirichlet 卷积
(f∗g)(n)=d∣n∑f(d)g(n/d)
Dirichlet 卷积有交换律,结合律,单位元 ε,逆元 f∗g=ε。
Dirichlet 卷积的计算可以通过枚举倍数的方式枚举约数,做到线性对数。
求逆元,已知 f,g(1)=1,递推
(f∗g)(n)d∣n∑f(d)g(n/d)f(1)g(n)+d∣n,d=1∑f(d)g(n/d)g(n)=ε(n)=0=0=−d∣n,d=1∑f(d)g(n/d)
借助单位元非 1 函数值为零进行构造。
两积性函数的 Dirichlet 卷积仍为积性函数。积性函数的逆仍为积性函数。
莫比乌斯函数
μ=I−1⟺d∣n∑μ(d)=[n=1]
根据 μ∗I=ε,其在素数幂次处的取值
μ(1)=1μ(p)I(1)+μ(1)I(p)=0⟹μ(p)=−1i=0∑kμ(pi)=0⟹μ(pk)=0
即可得到其定义
μ(n)={0(−1)k∃d>1,d2∣nk=∑i[pi∣n]
本质上,将一个数论函数 f 卷上 I 得到的 f∗I 即为约数意义下的前缀和。若将数的唯一分解视作高维点,前缀和即为所有偏序的点的函数值之和。相对应的 g 卷上 μ 即为差分,对于每个素因子容斥的结果。
f∗I=gg(n)=d∣n∑f(d)⟺f=g∗μ⟺f(n)=d∣n∑μ(n/d)g(d)
神秘的倍数求和(后缀和)及倍数差分
g(n)f(n)=n∣d∑f(d)=n∣d∑μ(d/n)g(d)
意思差不多。
gcd 卷积(?)
线性筛(?)
嵌入式莫比乌斯反演(?)
反演动机
[i⊥j]=[gcd(i,j)=1]=ε(gcd(i,j))=d∣gcd(i,j)∑μ(d)=d∣i,d∣j∑μ(d)
用她来拆 φ 的定义式
φ(n)=i=1∑n[i⊥n]=i=1∑nd∣i,d∣n∑μ(d)=d∣n∑i=1∑n[d∣i]μ(d)=d∣n∑(n/d)μ(d)
可得 φ=id∗μ,即 φ∗I=id
d∣n∑φ(d)=n
上式可以通过枚举 gcd 来理解
n=i=1∑n1=g∣n∑i=1∑n[gcd(i,n)=g]=g∣n∑g∣i∑[gcd(i/g,n/g)=1]=g∣n∑φ(n/g)=d∣n∑φ(d)
带入 n=gcd(a,b) 可得
gcd(a,b)=d∣gcd(a,b)∑φ(d)=d∣a,d∣b∑φ(d)
求和
i=1∑ngcd(i,n)=i=1∑nd∣i,d∣n∑φ(d)=d∣n∑i=1∑n[d∣i]φ(d)=d∣n∑(n/d)φ(d)=(id∗φ)(n)
同样的,我们可以枚举 gcd
i=1∑ngcd(i,n)=g∣n∑gi=1∑n[gcd(i,n)=g]=g∣n∑gg∣i∑[gcd(i/g,n/g)=1]=g∣n∑gφ(n/g)=(id∗φ)(n)
借助 φ 代表 gcd 为 1 进行化简。
欧拉函数的计算。考虑素数幂次 pk 取值,想要与其互质当且仅当不含素因子 p,其他(不互质)的数在 [1,pk] 共 pk/p=pk−1 个,故 φ(pk)=pk−pk−1=(p−1)pk−1。
另一个形式 p∣n⟹φ(pn)=p×φ(n)。
约数函数相关结论
σkd(n)σ(n)d(n)=idk∗I⟹d=I∗I=i∏d(piνp(i))=i∏(νp(i)+1)=i∏σ(piνp(i))=i∏j=0∑νp(i)pj=i∏pi−1piνp(i)+1−1=i=1∑n⌊in⌋