数论
算法
记号与定义
\(a\ mod\ p\):\(a\) 除 \(p\) 的余数,等于 \(a - p \times \lfloor \frac{a}{p} \rfloor\)。
\(a \mid b\):\(a\) 整除 \(b\) 即\(a\) 是 \(b\) 的因数。
非平凡因子:除了 1 和 其 本身以外的因子。
素数判定
试除法
对于任意整数 \(n\),它的因数 \(d,\frac{n}{d}\) 总是成对出现,所以可以枚举 \([2,\sqrt{n}]\) 内的数,逐一判断是不是 \(n\) 的因数即可。
费马素性测试
属于概率性测试,根据费马小定理实现。
对于任意整数 \(n\),从 \([2,n-1]\) 中取数 \(a\) 作为基,如果满足 \(a^{n-1}\equiv 1(\mod n)\),则通过这一轮测试,如果所有测试均通过,那么认为 \(n\) 是一个素数。
Miller-Rabin 素性测试
费马素数测试还是会漏掉一些合数(满足费马小定理),这些数被称为费马伪素数。
所以就有了 Miller-Rabin 素性测试,这里引入了新的定理:
二次探测定理:对于一个质数 \(p\),\(x^2 \equiv1(mod\ p)\) 小于 \(p\) 的解只有两个,\(x_1=1,x_2=-1\)。
proof: 移项得 \((x+1)(x-1) = 0 (mod\ p)\),又因为 \(p \in prime\), 所以 \(x+1,x-1\) 要么是 \(0\) 要么比 \(p\) 大,所以命题得证。
根据二次探测定理,如果 \(p\) 通过了费马检测,那么 \(p-1\) 会是个偶数(特判 \(2\)),所以就可以二次探测 \(a^{\frac{p-1}{2}} \equiv 1(mod\ p)\)、\(a^{\frac{p-1}{4}} \equiv 1(mod\ p)\)……直到出现奇数。
也就是说我们只需要把 \(p-1\) 拆分为 \(u \times 2^t\),判断 \(a^u,a^{u \times 2},a^{u \times2^2}\) 解的情况即可,他们的值要么都是 \(1\),要么在第一次出现 \(p-1\) 后都是 \(1\) 并且之前没有 \(1\),注意到这里不能出现 \(p\) 的倍数,更不能在最后一个数上出现 \(p-1\),否则不满足费马小定理。
code:
int fsp(int x, int k, int p){
int res = 1;
while(k){
if(k & 1) res = res * x % p;
k >>= 1;
x = x * x % p;
}
return res;
}
int bs[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
bool mrt(int n){
if(n < 3 or (n & 1) != 1) return n == 2;
int u = n - 1, cnt = 0;
while((u & 1) != 1) u >>= 1, cnt++;
for(auto i: bs){
int tmp = fsp(i, u, n);
if(tmp == 1 or tmp == n - 1 or tmp == 0) continue;
for(int j = 1; j <= cnt; j++){
tmp = tmp * tmp % n;
if(tmp == n - 1 and j != cnt){tmp = 1; break;}
if(tmp == 1) return 0;
}
if(tmp != 1) return 0;
}
return 1;
}
期望复杂度 \(O(\log n)\),同时也是个随机测试,但是在使用了上述几个底数后,在 OI 范围内出错的概率是 \(0\)。
因数分解
试除法
同上,每次找出一个因子后给原数除去并计入答案即可,时间复杂度 \(O(\sqrt n)\)。
Pollard rho 算法
首先介绍生日悖论:\(23\) 个人中,有两个人生日在同一天的概率超过 \(50%\),如果有 \(60\) 或更多的人,则概率大于 \(99%\)。
考虑一个数 \(k,gcd(k,n)\) 肯定是 \(n\) 的一个因子,至于怎么取这个 \(k\), 考虑随机选取。
我们通过一个函数 \(f(x) = (x^2+c)\ mod\ n\) 生成随机数,为什么选他呢,因为一个性质:
所以根据生日悖论,序列中不同的值数目 \(\leq \sqrt n\),把这个序列对 \(n\) 的最小非平凡因子 \(m\) 取模,期望不同的数个数 \(\leq n ^{\frac{1}{4}}\)。
所以我们可以在期望 \(O(n^\frac{1}{4})\) 的时间内找到两个位置 \(i,j\) 使得 \(gcd(n,\mid x_i-x_j \mid)\) 为 \(n\) 的一个非平凡因子。
每次随机选取 \(c\),期望复杂度 \(O(n^{\frac{1}{4}})\)。
可以通过倍增优化求 gcd。
所以我们可以每隔一段时间集中处理 gcd 以优化算法。
code:LuoguP4718
#include <bits/stdc++.h>
#define LHK_AK_IOI true
#define int long long
const int mod = 998244353;
const __int128 O = 1;
using namespace std;
inline int read( ){
int x = 0 ; short w = 0 ; char ch = 0;
while( !isdigit(ch) ) { w|=ch=='-';ch=getchar();}
while( isdigit(ch) ) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return w ? -x : x;
}
mt19937_64 rad(time(0));
int T;
int fac;
int fsp(int x, int k, int p){
int res = 1;
while(k){
if(k & 1) res = O * res * x % p;
k >>= 1;
x = O * x * x % p;
}
return res;
}
int gcd(int a, int b){return (b == 0 ? a : gcd(b, a % b));}
int bs[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
bool mrt(int n){
if(n < 3 or (n & 1) != 1) return n == 2;
int u, cnt;
cnt = __builtin_ctzll(n - 1);
u = (n - 1) >> cnt;
for(auto i: bs){
int tmp = fsp(i, u, n);
if(tmp == 1 or tmp == n - 1 or tmp == 0) continue;
for(int j = 1; j <= cnt; j++){
tmp = O * tmp * tmp % n;
if(tmp == n - 1 and j != cnt){tmp = 1; break;}
if(tmp == 1) return 0;
}
if(tmp != 1) return 0;
}
return 1;
}
int poll(int x){
int s = 0, t = 0, val = 1;//s, t 是两个位置,val 是差值
int c = rad( ) % (x - 1) + 1;// 常数
for(int i = 1;; i <<= 1, s = t, val = 1){//倍增阶段
for(int j = 1; j <= i; j++){// 步长
t = (O * t * t + c) % x;// f(x)
val = (O * val * abs(t - s)) % x;// gcd(ac % b, b) = gcd(ac, b)
}
int d = gcd(val, x);
if(d > 1) return d;
}
}
void rho(int x){
if(x <= fac or x < 2) return;
if(mrt(x)) return (void)(fac < x && (fac = x));//fac = max(fac, x);
int p = x;
while(p >= x) p = poll(x);
while(x % p == 0) x /= p;
rho(x); rho(p);
}
signed main( ){
T = read();
while(T--){
int x = read( );
fac = 0; rho(x);
if(fac == x) printf("Prime\n");
else printf("%lld\n",fac);
}
return (0-0);
}
同余
逆元
逆元,即满足 \(aa^{-1} \equiv 1 (mod\ b)\) 的 \(a^{-1}\),通常有三种求法:
- 求解 \(ax \equiv 1 (mod\ b)\) 即 \(ax + by = 1\);
- 费马小定理,快速幂求 \(a^{p-2} \equiv 1(mod\ p)\)
- 线性求逆元 \(inv_i = (p - \lfloor \frac{p}{i} \rfloor *inv_{p \ mod\ i})\ mod \ p\)
最大公约数(gcd)与最小公倍数(lcm)
更相减损法
proof:
令 \(d = gcd(a,b), a = k_1d, b = k_2d\)
\(a - b = k_1d - k_2d = (k_1 - k_2)d\) 且 \(d \mid (k_1 - k_2)d\)
所以 \(d\) 是 \(a - b\) 的因数,因为 \((k_1 - k_2) \nmid k_1\) 且 \(d = gcd(a,b)\),所以 \(gcd(a, b) = gcd(b, a - b)\)。
辗转相除法
proof:根据更相减损法,\(gcd(a, b) = gcd(b, a - kb) = gcd(b, a\ mod\ b)\),定理得证。
关于 \(lcm\):\(lcm(a,b) = \frac{a \times b}{gcd(a, b)}\)
裴蜀定理
\(ax + by = gcd(a,b)\) 一定有解。
拓展欧几里得算法
求解二元一次不定方程:$ ax+by=c $
先求解 \(ax+by=gcd(a,b) = d\) 得到 \(x_0, y_0\) 两个解
继续同乘 \(\frac{c}{d}\) 得到\(\frac{acx_0}{d} +\frac{bcy_0}{d} = c\)
所以 \(ax+by = c\) 的解就是 \(x_1 = \frac{x_0c}{d}, y_1 = \frac{y_0c}{d}\)
所以构造通解 \(a(x_1+kb)+b(y_1-ka)=c\) 其中 \(ka\) 和 \(kb\) 为整数
当 \(k\) 取道最小值的时候能保证相邻两个解之间相差 \(kb\)、\(k a\)
所以 \(d_x=kb=\frac{b}{d},d_y=ka=\frac{a}{d},k=\frac{1}{d}\)
那么通解就是
如果要是有正整数解的话就是
转化一下
离散对数与剩余
BSGS 算法及其扩展
BSGS有 998244353 种读法你晓得吗
求同余方程\(A^x \equiv B \ (mod \ C)\) 的解,其中 \(A、C\) 互质。
暴力枚举 \(x\), 复杂度是 \(O(nlogn)\),考虑优化。
令 \(m = \lceil\sqrt{C}\rceil, r = x\ mod\ m\),有:
我们就可以预处理出 \(BA^{r}\) 用哈希/桶维护一下,之后枚举 \(k\) 在表里找有没有对应的值就ok,时间复杂度\(O(\sqrt{C}\log{C})\)。
但是当 \(A、C\) 不互质的时候 \(A\) 的逆元可能不存在,这时候就需要 \(EXBSGS\)。
令 \(d = gcd(A,C)\), 如果 $\ d \nmid B\ $ 则无解,
之后原式就可以化成
所以
如果还不互质就继续减,最后就是
之后就可以 BGSG 做了。
二次剩余
令 \(x^k\equiv a(mod\ b)\) 成立的 \(a\) 称为模 \(b\) 的 \(k\) 次剩余,否则称为 \(k\) 次非剩余。
二次剩余是 \(k = 2\) 时的特殊情况,相当于是模意义下的开根运算。
勒让德符号:
Legendre 符号满足完全积性。
欧拉判别法则:
根据欧拉判别法则我们能快速的判断一个数是否是模 \(p\) 的二次剩余。
二次互反律:
Cipolla 算法
给定 \(a, b\) 求所有的 \(x\) 满足 \(x^2\equiv a\mod b\)。
算法流程很简单,首先 rand 一个 \(x_0\) 使得 \(\left(\frac{x_0^2 - a}{b}\right) = -1\),此时令 \(w = \sqrt{x_0^2-a}\)
最后结果是 \(x \equiv (x_0 + w)^{\frac{b+1}{2}}(mod\ b)\)。
考虑到模意义下的开根并没有意义,就像 \(\sqrt{-1}\) 一样,欸,\(\sqrt{-1}\) 不就是 \(i\) 嘛,所以我们考虑套用复数那套方法,引入一个新的域,在这个域内 \(w\) 存在,可以证明这个域确实是存在的。
最后的问题就是:为什么 \(x \equiv (x_0 + w)^{\frac{b+1}{2}}(mod\ b)\) 成立?这里浅证一下
两个前置结论:
\(w^b \equiv -w(mod\ b)\)
\((a+b)^k\equiv a^b+b^k(mod\ p)\)
读者自证不难。
期望复杂度 \(O(log^2n)\),注意实现的时候需要手写”复数“。
定理
威尔逊定理及其扩展*
\((p-1)!\equiv -1\ (mod\ p), p \in prime\)
欧拉定理及其扩展
约定欧拉函数 \(\varphi(x)\) 表示 \([1,x]\) 之间有多少与 \(x\) 互质的数。
欧拉定理:
拓展欧拉定理:
费马小定理:\(p \in prime, a^{p-1} \equiv 1\ (mod\ p)\),前提是 a 不是 p 的倍数,欧拉定理的特殊情况。
中国剩余定理(CRT)及其扩展
CRT:求解线性同余方程组:
其中\(m_1,m_2...m_k\)互质。
约定:\(M_i = \frac{\Pi_{j = 1} ^ k m_j}{m_i}, t_i = M_i^{-1}\ mod \ m_i\)
考虑将整个方程组拆成k个方程组,构造一组特解:
这个方程组有一个解为\(M_1 * t_1 * a_1\),那么把这 k 个方程组合并,原方程组的解就是:
EXCRT:\(m_1,m_2...m_k\) 不互质。
取其中两个同余方程
转化一下
联立
化简
是一个形如 \(ax + by = c\) 的二元一次不定方程,用 \(exgcd\) 求解,注意这里存在无解的情况。
之后求得通解
代回原式
转化
由此我们又构造了一个形如 \(x \equiv a(mod\ m)\) 的同余方程,方程数量-1,以此类推,最后会得到这样一个柿子
就解决辣
Lucas 定理及其扩展*
lucas定理:
数论函数
数论函数基础
基本概念:
积性函数:\(f(a) f(b) = f(ab),gcd(a,b) = 1\)
完全积性函数:\(f(a) f(b) = f(ab)\)
加性函数:\(f(a)+f(b) = f(ab),gcd(a, b) = 1\)
\(f*g=h\),若 \(f,g\) 都是积性函数,则 \(h\) 也是积性函数。
常见的数论函数:
函数 | 性质&&定义 |
---|---|
\(id_k(n)\) | \(n^k\),\(id_1(n)\) 记作 \(id(n)\) |
\(I(n)\) | \(I(n) = 1\), 单位函数 |
\(\sigma_k(n)\) | \(\sum_{d|n}d^k\),\(\sigma_0(n)\) 记作 \(d(n)\) |
\(\mu(n)\) | \(\begin{cases}1&n = 1\\0&n存在平方因子\\(-1)^{n的质因子数}&n不存在平方因子\end{cases}\) |
\(\epsilon(n)\) | \([n=1]\) ,单位元函数 |
\(\varphi(n)\) | \([1,n]\) 中与 \(n\) 互质的数的个数 |
迪利克雷卷积:
\((f*g)(n) = \sum_{d|n}f(d)g(\frac{n}{d})\)
常用的迪利克雷卷积:
卷积 | 证明 && 备注 |
---|---|
\(\mu * id = \varphi\) | 根据逆元可得 |
\(\varphi * I = id\) | 证明2 |
\(I*I=\sigma\) | 易证 |
\(\mu*I = \epsilon\) | \(\mu\) 是 \(I\) 的逆元,证明1 |
证明1:
当 \(n = 1\) 时显然成立。
设 \(n\) 有 \(k\) 个质因子。
证明2:proof
筛法
参考 筛法
参考文献
https://oi-wiki.org/math/number-theory/basic/
https://www.luogu.com.cn/blog/command-block/mu-bi-wu-si-fan-yan-ji-ji-ying-yong