数学数论学习笔记
平方和公式
$\sum n^2=\frac{n*(n+1)*(2n+1)}{6}$
立方和公式
$\sum n^3=(\frac{n*(n+1)}{2})^2$
一些推导
$\sum_{i}^{n}\sum_{j}^{n}ij=\sum_{i}^{n}i^3$
证明:对于一个$i$,它对答案的贡献为$i\cdot [(\sum_{j}^{i-1}j)+(\sum_{j}^{i}j)]$
因为前$i-1$个数分别会乘一次$i$,$i$又会将$1$到$i$全乘一遍,贡献就是它们的和
$i\cdot [(\sum_{j}^{i-1}j)+(\sum_{j}^{i}j)]=i\cdot (\frac{i(i-1)}{2}+\frac{i(i+1)}{2})=i^3$
线性筛素数
for (int i = 2; i <= N; i++) { if (!st[i]) prime.pb(i); for (int j = 0; j < prime.size(), prime[j] * i <= N; j++) { st[prime[j] * i] = true; if (i % prime[j] == 0) break; } }
反素数与因子个数
n的质因数分解为$n=p_{1}^{k_{1}}+p_{2}^{k_{2}}+...+p_{m}^{k_{m}}$
则n的因子个数为$(k_{1}+1)*(k_{2}+1)*...*(k_{m}+1)$
线性筛因子个数
d[1] = 1;//d为因子个数 for (int i = 2; i <= n; ++i) { if (!v[i]) v[i] = 1, p[++tot] = i, d[i] = 2, num[i] = 1; for (int j = 1; j <= tot && i <= n / p[j]; ++j) { v[p[j] * i] = 1; if (i % p[j] == 0) { num[i * p[j]] = num[i] + 1; d[i * p[j]] = d[i] / num[i * p[j]] * (num[i * p[j]] + 1); break; } else { num[i * p[j]] = 1; d[i * p[j]] = d[i] * 2; } } }
求因子数为n的最小数
prime[]= { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 }; dfs(0, 1, 1, 64); //ans为最后的答案 void dfs(ULL depth, ULL temp, ULL num, ULL up)//当前递归到的质因数 这些质因数结合得到的值 因子个数 上一个质因数的次方 { if (num > n || depth >= 16) return; if (num == n && ans > temp) { ans = temp; return; } for (int i = 1; i <= up; i++) { if (temp / prime[depth] > ans) break; dfs(depth + 1, temp = temp * prime[depth], num * (i + 1), i); } }
求n以内因子最多的最小数
prime[]= { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 }; dfs(0, 1, 1, 64); //ans为最后的答案 ans_num为最后的答案的因子数 void dfs(int depth, ULL temp, ULL num, int up) { if (depth >= 16 || temp > n) return; if (num > ans_num) { ans = temp; ans_num = num; } if (num == ans_num && ans > temp) ans = temp; for (int i = 1; i <= up; i++) { if (temp * prime[depth] > n) break; dfs(depth + 1, temp *= prime[depth], num * (i + 1), i); } return; }
欧几里得算法
最小公约数$gcd$:
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
最小公倍数$lcm$
int lcm(int a, int b) { return a * b / gcd(a, b); }
扩展欧几里得定理
求$ax+by=gcd(a,b)$的一组可行解
int exgcd(int a, int b, int& x, int& y) { if (!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; }
解线性同余方程
求解$ax\equiv c(\textit{mod b})$
$ax+by=c$等价于$ax\equiv c(\textit{mod b})$
通过扩展欧几里得可以求出一组可行解
若$gcd(a,b)=1$,且$x_0,y_0$为一组可行解,则该方程的任意解可以表示为$x=x_0+bt,y=y_0-at$且对于任意整数$t$都成立
求最小整数解,$x=(x\textit{ mod t}+t)\textit{mod t},t=\frac{b}{gcd(a,b)}$
欧拉函数
$\varphi (n)$为小于等于$n$的与$n$互质的数的个数
$\sum_{d|n} \varphi (d)=n$
他是积性函数,即若有$gcd(a,b)=1$,则$\varphi (a)*\varphi (b)=\varphi (a*b)$
当$n$为奇数时,$\varphi (2n)=\varphi (n)$
求解欧拉函数$\varphi (n)=n\prod_{i=1}^{s}(1-\frac{1}{p_{i}})$
其中$p_{i}$为n的质因数
线性筛欧拉函数
for (int i = 2; i <= n; i++) phi[i] = 0; phi[1] = 1; for (int i = 2; i <= n; i++) { if (!phi[i]) { for (int j = i; j <= n; j += i) { if (!phi[j]) phi[j] = j; phi[j] = phi[j] / i * (i - 1); } } }
欧拉定理
若$gcd(a,m)=1$,则$a^{\varphi (m)}\equiv 1(modm)$
扩展欧拉定理
$a^{b}\equiv \left\{\begin{matrix} a^{\textrm{b mod }\varphi (p)}\textit{ },gcd(a,p)=1 & \\ a^{b},gcd(a,p)\neq 1,b<\varphi (p) & \\ a^{\textit{b mod }\varphi (p)+\varphi (p)},gcd(a,p)\neq p,b>\varphi (p) & \end{matrix}\right.(\textit{mod p})$
费马小定理
若$gcd(a,p)=1$,则$a^{p-1}\equiv 1(\textit{mod p})$
求逆元可$a^{p-2}\equiv a^{-1}(\textit{mod p})$
裴蜀定理
$a,b$是不全为0的整数,则存在整数$x,y$使得$ax+by=c,gcd(a,b)|c$
线性求逆元
inv[1] = 1; for (int i = 2; i <= n; ++i) { inv[i] = (p - p / i) * inv[p % i] % p; }
线性求任意n个数的逆元
s[0] = 1; for (int i = 1; i <= n; ++i) s[i] = s[i - 1] * a[i] % p; sv[n] = qpow(s[n], p - 2); for (int i = n; i >= 1; --i) sv[i - 1] = sv[i] * a[i] % p; for (int i = 1; i <= n; ++i) inv[i] = sv[i] * s[i - 1] % p;
线性同余方程
求一组可行解,可以把$ax\equiv c(\textit{mod b})$看作$ax+by=c$,之后用扩展欧几里得,若不满足$gcd(a,b)|c$则无解
求所有解,任意解可表示为$x=x^{0}+bt$,$y=y^{0}+at$,其中$t\in \mathbb{Z}$
求最小解,$x=(\textit{x mod t+t})\textit{mod t}$,其中$t=\frac{b}{gcd(a,b)}$
中国剩余定理(CRT)
$m_{i}$两两互质,求$\left\{\begin{matrix}x\equiv a_{1}(\textit{mod }m_{1}) & \\ x\equiv a_{2}(\textit{mod }m_{2}) & \\ x\equiv a_{3}(\textit{mod }m_{3}) & \\ ... & \\ x\equiv a_{k}(\textit{mod }m_{k}) & \end{matrix}\right.$
伪代码:
$M=\prod m_{i}$
$\textit{for i=1 to k}$
$mi=\frac{M}{m_{i}}$
$b=inv(mi,m_{i})$
$ans=(ans+a[i]*mi*b)mod M$
扩展中国剩余定理
$m_{i}$两两不互质
int exCRT() { int x, y, k; int M = b[1], ans = a[1]; for (int i = 2; i <= n; i++) { int a = M, b = b[i], c = (a[i] - ans % b + b) % b; int gcd = exgcd(a, b, x, y), bg = b / gcd; if (c % gcd != 0) return -1; x = mul(x, c / gcd, bg); ans += x * M; M *= bg; ans = (ans % M + M) % M; } return (ans % M + M) % M; }
Lucas定理
当$p$为质数,$C\binom{n}{m}\equiv C\binom{n/p}{m/p}*C\binom{\textit{n mod p}}{\textit{m mod p}}\textit{mod p}$
扩展Lucas
待填
BSGS
基础
求$a^{x}\equiv b(\textit{mod p})$
令$x=A\left \lceil \sqrt{p} \right \rceil-B$,其中$0\leq A,B\leq \left \lceil \sqrt{p} \right \rceil$,则有$a^{A\left \lceil \sqrt{p} \right \rceil-B}\equiv b(\textit{mod p})$,转换成$a^{A\left \lceil \sqrt{p} \right \rceil}\equiv ba^{B}(\textit{mod p})$,之后算出$ba^{B}$的所有取值存下来,之后再枚举$A$,看是否有符合的$ba^{B}$,从而得到所有的$x$
int m = ceil(sqrt(p)); for (int i = 1; i <= m; i++) { hash1[qpow(a, i, p) * b % p] = i; } int q = qpow(a, m, p), ans = 1; for (int i = 1; i <= m; i++) { ans = 1ll * ans * q % p; if (hash1[ans]) { ans = i * m - hash1[ans]; printf("%lld", (ans % p + p) % p); return 0; } }
扩展BSGS
拉格朗日插值
由$n$个点$(x_{i},y_{i})$可以确定一个多项式$y=f(x)$,求$f(k)$的值,对$mod$取模
for (int i = 1; i <= n; i++) { s1 = y[i] % mod; s2 = 1ll; for (int j = 1; j <= n; j++) { if (i != j) { s1 = s1 * (k - x[j]) % mod, s2 = s2 * ((x[i] - x[j] % mod) % mod) % mod; } } ans += s1 * inv(s2) % mod; ans = (ans + mod) % mod; }
数论分块
用于求含有$\left \lfloor \frac{n}{i}\right \rfloor$的求和式($n$为常数)
找到一个最大的$j$,使得$\left \lfloor \frac{n}{i} \right \rfloor=\left \lfloor \frac{n}{j} \right \rfloor$
此时$j=\left \lfloor \frac{n}{\left \lfloor \frac{n}{i} \right \rfloor} \right \rfloor$
例如[Luogu 2261],求$ans=\sum_{i=1}^{n}(\textit{k mod i})=\sum_{i=1}^{n}k-i\left \lfloor \frac{k}{i} \right \rfloor$
int ans = n * k; for (int l = 1, r; l <= n; l = r + 1) //区间[l,r]内的k/i都相同 { if (k / l != 0) r = min(k / (k / l), n); else r = n; ans -= (k / l) * (r - l + 1) * (l + r) / 2; }
若求$\sum_{i=1}^{min(n,m)}\left \lfloor \frac{n}{i} \right \rfloor\left \lfloor \frac{m}{i} \right \rfloor$则把$r=n/(n/i)$换成$r=min(n/(n/i),m/(m/i))$
关于积性函数、狄利克雷卷积、莫比乌斯反演 铃悬的数学小讲堂——狄利克雷卷积与莫比乌斯反演 - 铃悬 的博客 - 洛谷博客 (luogu.com.cn)
为什么我觉得下面这三个知识点是数论最简单的东西
积性函数
定义
若函数$f(x)$满足$f(1)=1$且$\forall x,y\in \mathbb{N_{+}},gcd(x,y)=1$都有$f(x)*f(y)=f(xy)$,则称$f(x)$为积性函数
若函数$f(x)$满足$f(1)=1$且$\forall x,y\in \mathbb{N_{+}}$都有$f(x)*f(y)=f(xy)$,则称$f(x)$为完全积性函数
性质
若$f(x),g(x)$均为积性函数,则下列函数也为积性函数:
$h(x)=f(x^{p})$
$h(x)=f^{p}(x)$
$h(x)=f(x)g(x)$
$h(x)=h(x)=\sum_{d|x}f(d)g(\frac{x}{d})$
设$x=\prod p_{i}^{k_{i}}$,
若$F(x)$为积性函数,则$F(x)=\prod F(p_{i}^{k_{i}})$
若$F(x)$为完全积性函数,则$F(x)=\prod F(p_{i})^{k_{i}}$
Dirichlet卷积
两个数论函数$f,g$的Dirichlet卷积为
$(f*g)(n)=\sum_{d|n}f(d)g(\frac{n}{d})$
Dirichlet卷积满足以下性质
交换律$(f*g=g*f)$
结合律$(f*g)*h=f*(g*h)$
分配率$f*(g+h)=f*g+f*h$
$f*\varepsilon =f$,其中$\varepsilon$为Dirichlet卷积的单位元,定义为$\varepsilon(n)=[n=1]$
莫比乌斯函数
莫比乌斯函数$\mu $定义为
$\mu(n)=1,n=1$
$\mu(n)=0,n$含有次数超过$1$的因子
$\mu(n)=(-1)^{k},k$为$n$的次数为$1$的质因子个数
它是积性函数,且
$\sum_{d|n}\mu(d)=\left\{\begin{matrix}1,n=1 & \\ 0,n\neq 1 & \end{matrix}\right.$
反演结论:$\begin{bmatrix}gcd(i,j)=1\end{bmatrix}\Leftrightarrow \sum_{d|gcd(i,j)}\mu(d)$
线性筛莫比乌斯函数
mu[1] = 1; for (int i = 2; i <= n; ++i) { if (!flg[i]) p[++tot] = i, mu[i] = -1; for (int j = 1; j <= tot && i * p[j] <= n; ++j) { flg[i * p[j]] = 1; if (i % p[j] == 0) { mu[i * p[j]] = 0; break; } mu[i * p[j]] = -mu[i]; } }
莫比乌斯反演
两个数论函数$f(n),g(n)$
若$f(n)=\sum_{d|n}g(d)$,则$g(n)=\sum_{d|n}\mu(d)f(\frac{n}{d})$
若$f(n)=\sum_{n|d}g(d)$,则$g(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)$
例题:[HAOI 2011] Problem b ,[BAOJ 2154]Crash的数字表格,[SDOI2015]约数个数和,[Luogu 3768]简单的数学题
二次剩余
若存在$x$使得$x^{2}\equiv a(\textit{mod p})$,且$a$不是$p$的倍数,则称$a$为模$p$的二次剩余
求解二次剩余便是给出$a$求出$x$
解的数量:
对于$x^{2}\equiv n(\textit{mod p})$,能满足$n$是模$p$的二次剩余的$n$一共有$\frac{p-1}{2}$个
证明:
$(p-x)^{2}\equiv x^{2}(\textit{mod p})$,所以我们只看$x\in [1,\frac{p-1}{2}]$的情况
若存在$x,y$使得$x^{2}\equiv y^{2}(\textit{mod p})$
则有$x^{2}-y^{2}\equiv 0(\textit{mod p})$
$(x-y)(x+y)\equiv 0(\textit{mod p})$
因为$-p<x+y<p,-p<x-y<p,x+y\neq 0,x-y\neq $,所以不存在$x,y$使得$x^{2}\equiv y^{2}(\textit{mod p})$
勒让德符号:
$\left ( \frac{n}{p} \right )$
若其的值为$1$则$n$为二次剩余,若为$-1$则$n$不是二次剩余,若为$0$则$p|n$
欧拉判别:
$\left ( \frac{n}{p} \right )=n^{\frac{p-1}{2}}(\textit{mod p})$
证明:
求解二次剩余:
Cipolla算法:
定义$i^{2}=a^{2}-n$,则解为$(a+i)^{\frac{p+1}{2}}$
1 int t; 2 ll n, p; 3 ll w; 4 5 struct num { //建立一个复数域 6 ll x, y; 7 }; 8 9 num mul(num a, num b, ll p) { //复数乘法 10 num ans = {0, 0}; 11 ans.x = ((a.x * b.x % p + a.y * b.y % p * w % p) % p + p) % p; 12 ans.y = ((a.x * b.y % p + a.y * b.x % p) % p + p) % p; 13 return ans; 14 } 15 16 ll binpow_real(ll a, ll b, ll p) { //实部快速幂 17 ll ans = 1; 18 while (b) { 19 if (b & 1) ans = ans * a % p; 20 a = a * a % p; 21 b >>= 1; 22 } 23 return ans % p; 24 } 25 26 ll binpow_imag(num a, ll b, ll p) { //虚部快速幂 27 num ans = {1, 0}; 28 while (b) { 29 if (b & 1) ans = mul(ans, a, p); 30 a = mul(a, a, p); 31 b >>= 1; 32 } 33 return ans.x % p; 34 } 35 36 ll cipolla(ll n, ll p) { 37 n %= p; 38 if (p == 2) return n; 39 if (binpow_real(n, (p - 1) / 2, p) == p - 1) return -1; 40 ll a; 41 while (1) { //生成随机数再检验找到满足非二次剩余的a 42 a = rand() % p; 43 w = ((a * a % p - n) % p + p) % p; 44 if (binpow_real(w, (p - 1) / 2, p) == p - 1) break; 45 } 46 num x = {a, 1}; 47 return binpow_imag(x, (p + 1) / 2, p); 48 }
快速莫比乌斯变换FMT
一般用来解决类似于 $C_x=\sum_{i \cup j =x}A_iB_j$ 的问题,其中 $x,i,j$ 表示为集合
详解见 传送门
模板: ( $n$ 表示全集大小)
void FMT(int *A) { for (int i = 1; i < (1 << n); i <<= 1) for (int p = i << 1, j = 0; j < (1 << n); j += p) for (int k = 0; k < i; ++k) A[i + j + k] += A[j + k]; } void reFMT(int *A) { for (int i = 1; i < (1 << n); i <<= 1) for (int p = i << 1, j = 0; j < (1 << n); j += p) for (int k = 0; k < i; ++k) A[i + j + k] -= A[j + k]; } int main() { FMT(a), FMT(b); for (int i = 0; i < 1 << n; i++) a[i] *= b[i]; reFMT(a); // a即为要求的C }
扩展: (不一定正确)
$A_i$ 表示 $a$ 中状态为 $i$ 的方案数, $B_i$ 表示 $b$ 中状态为 $i$ 的方案数
求 $C_x=\sum_{i \& j=x}A_iB_j$
inline void FMT(int *a) { for (int j = 0; j < n; j++) for (int i = 0; i < 1 << n; i++) if (i >> j & 1) a[i & ~(1 << j)] += a[i]; } inline void reFMT(int *a) { for (int j = 0; j < n; j++) for (int i = 0; i < 1 << n; i++) if (i >> j & 1) a[i & ~(1 << j)] -= a[i]; } int main() { FMT(A), FMT(B); for (int i = 0; i < 1 << n; i++) A[i] *= B[i]; reFMT(A); }
快速沃尔什变换FWT
一般用来解决类似于$C_{i}=\sum_{j\bigoplus k}^{}A_{j}B_{k}$的问题,其中$\bigoplus$表示而二元位运算的一种
详解见OI_Wiki
与、或、异或运算皆是将$A$、$B$转换后,$C$便等于$A*B$,之后再给C来一遍逆转换即可
或:
当$flag =1$时为转换,$flag=-1$时为逆转换
for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) { for (int i = 0; i < n; i += o) { for (int j = 0; j < k; j++) { f[i + j + k] = add(f[i + j + k], mul(f[i + j], flag)); } } }
与:
同上
for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) { for (int i = 0; i < n; i += o) { for (int j = 0; j < k; j++) { f[i + j] = add(f[i + j], mul(f[i + j + k], flag)); } } }
异或:
当$flag=1$时为转换,当$flag=\frac{1}{2}$时为逆转换
for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) { for (int i = 0; i < n; i += o) { for (int j = 0; j < k; j++) { f[i + j] = add(f[i + j], f[i + j + k]); f[i + j + k] = sub(sub(f[i + j], f[i + j + k]), f[i + j + k]); f[i + j] = mul(f[i + j], flag), f[i + j + k] = mul(f[i + j + k], flag); } } }
实现:
其中$mul$是$a[i]*=b[i]$,与运算和异或运算类似
putin(a),putin(b);//输入 OR(a,1),OR(b,1);//转换 mul(a,b);//相乘 OR(a,-1);//逆转换 putout(a);//此时a=c,输出
阶
若$(a,m)=1$,使$a^l\equiv 1(\textit{mod m})$成立的最小的$l$称为$a$模$m$的阶,记为$ord_ma$
若$ord_ma=l$,则$ord_ma^t=\frac{l}{(t,l)}$
有欧拉定理,设$ord_ma=l$,则$a^n\equiv 1(\textit{mod m})$当且仅当$l|n$,特别的,$l|\varphi (m)$
设$p$是素数,$ord_pa=l$,那么当且仅当有$\varphi (l)$个关于模$p$的阶为$l$且两两互不同余的数
设$ord_ma=l$,则$1,a,a^2,···,a^{l-1}$关于模$m$两两互不同余
设$p$是素数,$l|\varphi (p)$,则存在$\varphi (p)$个关于模$p$的阶为$l$且两两互不同余的数
若$m=p_{1}^{a_1}p_{2}^{a_2}···p_{k}^{a_k}$,则$ord_ma=[ord_{p_1}^{a_1},ord_{p_2}^{a_2},···,ord_{p_k}^{a_k}]$
原根
$(g,m)=1$,若$ord_mg=\varphi (m)$,则$g$为$m$的一个原根
$g$为$m$的一个原根当且仅当${g,g^2,···,g^\varphi (m)}$构成模$m$的一个既约剩余系
判断是否有原根
若$m$有原根,则$m$一定为$2,4,p^a,2p^a$,其中$p$为奇素数,$a$为正整数
求一个原根
$(g,m)=1$,设$p_1,p_2,···,p_k$是$\varphi (m)$的所有不同的素因数,则$g$是$m$的原根,当且仅当任意$1\leq i\leq k$,都有$g^{\frac{\varphi(m)} {p_i}}\not\equiv 1(\textit{mod m})$
板子:[Luogu6091]
快速傅里叶变换(FFT)
#define PI acos(-1) struct Complex { double x, y; Complex(double x = 0, double y = 0) : x(x), y(y) { } }a[N]; Complex operator * (Complex J, Complex Q) { return Complex(J.x * Q.x - J.y * Q.y, J.x * Q.y + J.y * Q.x); } Complex operator - (Complex J, Complex Q) { return Complex(J.x - Q.x, J.y - Q.y); } Complex operator + (Complex J, Complex Q) { return Complex(J.x + Q.x, J.y + Q.y); } void FFT(Complex* A, int type) { for (int i = 0; i < limit; ++i) { if (i < R[i]) swap(A[i], A[R[i]]); } for (int mid = 1; mid < limit; mid <<= 1) { Complex wn(cos(PI / mid), type * sin(PI / mid)); for (int len = mid << 1, pos = 0; pos < limit; pos += len) { Complex w(1, 0); for (int k = 0; k < mid; ++k, w = w * wn) { Complex x = A[pos + k]; Complex y = w * A[pos + mid + k]; A[pos + k] = x + y; A[pos + mid + k] = x - y; } } } if (type == 1) return; for (int i = 0; i <= limit; ++i) a[i].x /= limit, a[i].y /= limit; } int main() { scanf("%d%d", &n, &m); for (int i = 0; i <= n; ++i) scanf("%lf", &a[i].x); for (int i = 0; i <= m; ++i) scanf("%lf", &a[i].y); limit = 1; while (limit <= n + m) limit <<= 1, L++; for (int i = 0; i < limit; ++i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1)); FFT(a, 1); for (int i = 0; i <= limit; ++i) a[i] = a[i] * a[i]; FFT(a, -1); for (int i = 0; i <= n + m; ++i) printf("%d ", (int)(a[i].y / 2 + 0.5)); }
快速数论变换(NTT)
用来快速计算卷积
卷积:类似于 $(f*g)(x)=\sum f(i)g(n-i)$ 的形式
void NTT(int *x, int lim, int opt) { register int i, j, k, m, gn, g, tmp; for (i = 0; i < lim; ++i) if (r[i] < i) swap(x[i], x[r[i]]); for (m = 2; m <= lim; m <<= 1) { k = m >> 1; gn = qpow(3, (P - 1) / m); for (i = 0; i < lim; i += m) { g = 1; for (j = 0; j < k; ++j, g = 1ll * g * gn % P) { tmp = 1ll * x[i + j + k] * g % P; x[i + j + k] = (x[i + j] - tmp + P) % P; x[i + j] = (x[i + j] + tmp) % P; } } } if (opt == -1) { reverse(x + 1, x + lim); register int inv = qpow(lim, P - 2); for (i = 0; i < lim; ++i) x[i] = 1ll * x[i] * inv % P; } } void solve() { while (lim < (n << 1)) lim <<= 1; for (int i = 0; i < lim; ++i) r[i] = (i & 1) * (lim >> 1) + (r[i >> 1] >> 1); NTT(A, lim, 1), NTT(B, lim, 1); for (int i = 0; i < lim; i++) C[i] = A[i] * B[i] % P; NTT(C, lim, -1); }
线性基
线性基有以下性质
对于一个数列 $A$ 来说,若$P$为它的线性基
$A$任意数字都能通过$P$中的一些数字异或出来
$P$只能异或出$A$中的数或$A$中的数能异或出来的东西
$P$中任意数都不能被$P$中其他数异或出来
$P$中数最高位不重复
构造线性基
inline void insert(LL x) { for (int i = 62; ~i; i--) { if ((x >> i) & 1) { if (!a[i]) { a[i] = x; break; } else x ^= a[i]; } } }
求数列的最大异或和
for (int i = 62; ~i; i--) ans = max(ans, ans ^ a[i]);
求异或的不同结果中第$k$小的数
inline void find_init()//初始化 { cnt = 0; for (int i = 0; i <= 62; ++i) { for (int j = i - 1; j >= 0; --j) if (a[i] & (1ll << j)) a[i] ^= a[j]; if (a[i]) tmp[cnt++] = a[i]; } } inline LL find_num(LL k)//查询 { LL res = 0; k -= flag; if (!k) return 0; if (k >= (1ll << cnt)) return -1; for (int i = 0; i < cnt; i++) { if ((k >> i) & 1) res ^= tmp[i]; } return res; }
生成函数
若一个序列为$a=\begin{Bmatrix} a_1,a_2,a_3,a_4,...,a_n \end{Bmatrix}$
则它的生成函数为$F(x)=a_1+a_2x+a_3x^2+a_4x^3+...+a_nx^{n+1}$
若$a=\begin{Bmatrix} 1,1,1,1,1,... \end{Bmatrix}$
则它的生成函数为$F(x)=1+x+x^2+x^3+x^4+...=\frac{1}{1-x}$
因为$F(x)x+1=F(x)$
解得$F(x)=\frac{1}{1-x}$
其他
$F(x)=1+ax+2ax^2+3ax^3+4ax^4+...=\frac{1}{(1-x)^a}=\sum_{n}^{\infty }C_{n+a-1}^{a-1}x^n,a$为一个常数,则第$n$项的系数为$C_{n+a-1}^{a-1}$
$F(x)=1+x^a+x^{2a}+x^{3a}+...=\frac{1}{1-x^a}$,$a$为一个常数
常见的生成函数
$<1,1,1,1,1,\dots>,F(x) = \sum_{n\geq 1}x^n=\frac{x}{1-x}$
$<1,0,1,0,1,\dots>,F(x) = \sum_{n\geq 0}x^{2n}=\frac{1}{1-x^2}$
$<1,2,3,4,\dots>,F(x) = \sum_{n\geq 0}(n+1)x^n=\frac{1}{(1-x)^2}$
$a_n=\binom{m}{n},F(x)=\sum_{n\geq0}\binom{m}{n}x^n=(1+x)^m$
$a_n=\binom{m+n}{n},F(x)=\sum_{n\geq0}\binom{m+n}{n}x^n=\frac{1}{(1-x)^{m+1}}$
生成函数一般用来求方案数
例如:
有$n$种砝码,每种砝码个数无限,质量分别为$1~n$克,用序列$a_i$表示第$i$个砝码能组成$m$克的方案数为$a_{i,m+1}$
例:
$1$克的砝码的序列为$a=\begin{Bmatrix} 1,1,1,1,1,1,1,... \end{Bmatrix}$,每种质量它都能有一种方案组成
$3$克的砝码的序列为$a=\begin{Bmatrix} 1,0,0,1,0,0,1,0,0,1,... \end{Bmatrix}$,$3$克的砝码组成$0$克的方案数为$1$,则$a_{3,1}=1$,组成$1,2$的方案数为$0$,则$a_{3,2}=0,a_{3,3}=0$,组成$3$克的方案数为$1$,则$a_{3,4}=1$
接下来求生成函数
$1$克的生成函数便是$F_1(x)=1+x+x^2+x^3+...=\frac{1}{1-x}$
$3$克的生成函数为$F_3(x)=1+x^3+x^6...=\frac{1}{1-x^3}$
之后$\prod_{i=1}^{n}F_i(x)$便是$n$个砝码全部都用的生成函数,之后求出$x^m$的系数,该系数就是答案
置换
Burnside 引理
每个置换的不动点个数的平均数就是方案数
斯特林数
第一类斯特林数
$\begin{bmatrix}n\\ k\end{bmatrix}$或$s(n,k)$,表示将$n$个两两不同的数分为$k$个互不区分的非空轮换的方案数
一个轮换指首尾相连的环形序列,$[A,B,C,D]$视为一个轮换,则$[A,B,C,D]=[B,C,D,A]=[C,D,A,B]=[D,A,B,C]$,$[A,B,C,D]\neq [D,C,B,A]$
$\begin{Bmatrix}n\\ k\end{Bmatrix}=\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}+(n-1)\begin{Bmatrix}n-1\\ k\end{Bmatrix}$
第二类斯特林数
$\begin{Bmatrix}n\\ k\end{Bmatrix}$或$S(n,k)$,表示将两两不同的$n$个数分为$k$个不同的非空子集的方案数
$\begin{Bmatrix}n\\ k\end{Bmatrix}=\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}+k\begin{Bmatrix}n-1\\ k\end{Bmatrix}$
通项公式$\begin{Bmatrix}n\\ m\end{Bmatrix}=\sum_{i=0}^{m}\frac{(-1)^{m-i}i^n}{i!(m-i)!}$
用途
上升幂与普通幂转换
上升幂:$x^{\bar n}=\prod_{k=0}^{n-1}(n+k)$
$x^n=\sum_{k}\begin{Bmatrix}n\\ k\end{Bmatrix}(-1)^{n-k}x^{\bar{k}}$
$x^{\bar{n}}=\sum_{k}\begin{bmatrix}n\\ k\end{bmatrix}x^k$
下降幂与普通幂转换
下降幂:$x^{\underline n}=\frac{x!}{(x-n)!}=\prod_{k=0}^{n-1}(n-k)$
下降幂一特性:$\binom{n}{k} \cdot k^{\underline{i}}=\binom{n-i}{k-i} \cdot n^{\underline{i}}$
$x^{n}=\sum_{k}\begin{Bmatrix}n\\ k\end{Bmatrix}x^{\underline k}$
$x^{\underline n}=\sum_{k}\begin{bmatrix}n\\ k\end{bmatrix}(-1)^{n-k}x^k$
求$x_n=ax_{n-1}+b$的通项公式
$x_n=ax_{n-1}+b$
设$x_n+c=a(x_{n-1}+c)$
$x_n=ax_{n-1}+c(a-1)$
$c(a-1)=b$
$c=\frac{b}{a-1}$
$x_n+\frac{b}{a-1}=a(x_{n-1}+\frac{b}{a-1})$
$x_n+\frac{b}{a-1}=a^2(x_{n-2}+\frac{b}{a-1})$
$...$
$x_n+\frac{b}{a-1}=a^{n-1}(x_1+\frac{b}{a-1})$
行列式
定义:$n$阶行列式是由$n^2$个数$a_{ij}$通过下式确定的一个数
$\begin{vmatrix} a_{11}& a_{12} & ... & a_{1n} & \\ a_{21}& a_{22} & ... & a_{2n} & \\ \vdots & \vdots &\ddots & \vdots & \\ a_{n1}& a_{n2} & ... & a_{nn} & \end{vmatrix}=\sum_{j_1j_2...j_n}(-1)^{\gamma (j_1...j_n)}a_{1j_1}a_{2j_1}...a_{nj_1}$
$j_1j_2...j_n$是$1-n$的一个排列,$\gamma (j_1...j_n)$是排列中逆序对的个数
基本定理:
$1$ 行列互换,值不变
$2$ 用一个数乘行列式的某行等于用这个数乘此行列式
$3$ 如果行列式中某一行是两组数之和,则这个行列式等于两个行列式之和,这两个行列式分别以这两组数为该行,而其余各行与原行列式对应各行相同
$4$ 交换行列式中两行,行列式反号(乘$-1$)
$5$ 如果行列式中有两行成比例,则行列式为0
$6$ 把一行的某个倍数加到另一行,行列式的值不变
求行列式的值:
高斯消元,每次将两行交换的时候改变行列式的符号,消到最后行列式的值就为$\prod a_{i,i}$乘上符号
for (int i = 0; i < n; ++i) { int k = i; for (int j = i + 1; j < n; ++j) if (abs(a[j][i]) > abs(a[k][i])) k = j; if (abs(a[k][i]) < EPS) { det = 0; break; } swap(a[i], a[k]); if (i != k) det = -det; det *= a[i][i]; for (int j = i + 1; j < n; ++j) a[i][j] /= a[i][i]; for (int j = 0; j < n; ++j) if (j != i && abs(a[j][i]) > EPS) for (int k = i + 1; k < n; ++k) a[j][k] -= a[i][k] * a[j][i]; }
不带实数运算的求行列式的值
int det = 1; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { while (a[i][i]) { int d = a[j][i] / a[i][i]; for (int k = i; k < n; k++) { a[j][k] = (a[j][k] - 1ll * d * a[i][k] % mod + mod) % mod; } swap(a[i], a[j]); det = -det; } swap(a[i], a[j]); det = -det; } } for (int i = 0; i < n; i++) det = 1ll * det * a[i][i] % mod; return det;
二项式定理
$(a+b)^n=\sum_{i=0}^n\binom{n}{i}a^{n-i}b^i$
二项式反演
$f_n=\sum_{i=0}^n(-1)^iC_n^ig_i \Leftrightarrow g_n=\sum_{i=0}^n(-1)^iC_n^if_i$
$f_n=\sum_{i=0}^nC_n^ig_i \Leftrightarrow g_n=\sum_{i=0}^n(-1)^{n-i}C_n^if_i$
$\forall m \geq n,f_n=\sum_{i=n}^mC_i^ng_i \Leftrightarrow g_n=\sum_{i=n}^m(-1)^{i-n}C_i^nf_i$