同步于 博客园 和 洛谷博客 。
由于各网站之间 LaTeX \LaTeX L A T E X 及 Markdown 渲染方式的差异,故不保证除博客园外的排版完好,对于排版有明显不正确的地方请以博客园为主。
质数
定义 :无法被任何除了 1 1 1 及其本身的自然数整除的数。
性质:
[ 1 , n ] [1,n] [ 1 , n ] 内大约有 n ln n \frac{n}{\ln n} l n n n 个质数,即每 ln n \ln n ln n 个数就大约有一个质数。
判断质数
试除法 :
时间复杂度 O ( n ) \mathcal{O}(\sqrt{n}) O ( n ) 。
1 2 3 4 5 6 7 bool isPrime (int n) { if (n<2 ) return 0 ; int k=sqrt (n); F (i,2 ,k) if (!(n%i)) return 0 ; return 1 ; }
质数筛
埃氏筛 :
对于每个整数,显然其倍数都不是质数。
扫描所有数,每扫到一个没被标记的数,该数即为质数,随后标记该数的倍数为约数。
同时,对于当前的质数 x x x ,因为小于 x 2 x^2 x 2 的 x x x 的倍数已经被小于 x x x 的质数扫描过了,因此只需要从 x 2 x^2 x 2 开始扫描倍数即可。
时间复杂度 O ( n log log n ) \mathcal{O}(n\log \log n) O ( n log log n ) 。
1 2 3 4 5 6 7 8 bool vis[N];void EratosthenesSeive (int n) { F (i,2 ,n){ if (vis[i]) continue ; F (j,i,n/i) vis[i*j]=1 ; } return ; }
线性筛(欧拉筛) :
埃氏筛依旧会重复标记某些合数,考虑使合数被唯一标记。
设 v i v_i v i 为 i i i 的最小质因子,从前到后扫描所有数,若 v i = 0 v_i=0 v i = 0 则 i i i 为质数,使 v i = i v_i=i v i = i 并将 i i i 加入到质数集 Prime \text{Prime} Prime 。
对于每个数,扫描质数集的所有数 x x x ,若 x x x 相比 v i v_i v i 不是最小的质因子或 i × x i\times x i × x 超出筛的范围则终止扫描,反之则 v i × x = x v_{i\times x}=x v i × x = x 。
时间复杂度 O ( n ) \mathcal{O}(n) O ( n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 vector<int > prime;int v[N];void EulerSeive (int n) { F (i,2 ,n){ if (!v[i]) v[i]=i,prime.push_back (i); V (x,prime){ if (x>v[i]||i*x>n) break ; v[i*x]=x; } } return ; }
质因数分解
前置知识 :
唯一分解定理 :任意一个大于 1 1 1 的正整数 n n n 都可被唯一分解为若干个质数的乘积,即 n = p 1 c 1 p 2 c 2 … p k c k n=p_1^{c_1}p_2^{c_2}\dots p_k^{c_k} n = p 1 c 1 p 2 c 2 … p k c k ,其中 c i c_i c i 为正整数,p i p_i p i 为质数且 p 1 < p 2 < ⋯ < p k p_1 < p_2 < \dots < p_k p 1 < p 2 < ⋯ < p k 。
1 2 3 4 5 6 7 8 9 10 11 12 int p[N],c[N],tot;void Divide (int n) { int k=sqrt (n); F (i,2 ,k){ if (!(n%i)){ p[++tot]=i,c[tot]=0 ; while (!(n%i)) ++c[tot],n/=i; } } if (n>1 ) p[++tot]=n,c[tot]=1 ; return ; }
约数
定义 :若 n m o d d = 0 n\bmod d=0 n mod d = 0 ,则称 d d d 为 n n n 的约数,记作 d ∣ n d\mid n d ∣ n ,读作 d d d 整除 n n n 。
求单个值的正约数集合
试除法 :
因为若 d d d 为 n n n 的约数,则 n d \frac{n}{d} d n 也为 n n n 的约数,所以除完全平方数的 n \sqrt n n 之外,约数总是成对出现的。
故从 1 ∼ n 1\sim \sqrt n 1 ∼ n 判断 i i i 是否整除 n n n 即可,若整除且 i ≠ n i i\neq \frac{n}{i} i = i n 则 n i \frac{n}{i} i n 也为约数。
推论 :一个整数 n n n 至多有 2 n 2\sqrt n 2 n 个约数。
时间复杂度 O ( n ) \mathcal{O}(\sqrt n) O ( n ) 。
1 2 3 4 5 6 7 8 9 10 11 vector<int > fac;void FactorDivision (int n) { int k=sqrt (n); F (i,1 ,k){ if (!(n%i)){ fac.push_back (i); if (i!=n/i) fac.push_back (n/i); } } return ; }
求区间内的正约数集合
暴力+试除法 :
时间复杂度 O ( n n ) \mathcal{O}(n\sqrt n) O ( n n ) ,代码见求单个值的正约数集合 。
倍数法 :
反过来考虑,运用埃氏筛的倍数标记思想,对于每个数 d d d ,d d d 肯定为其的倍数的约数,故对于每个数,将这个数加入到这个数的倍数的正约数集合里。
时间复杂度 O ( n log n ) \mathcal{O}(n\log n) O ( n log n ) 。
1 2 3 4 5 6 7 vector<int > fac[N];void FactorDivision (int n) { F (i,1 ,n) F (j,1 ,n/i) fac[i*j].push_back (i); return ; }
数论分块
例题 :给定正整数 n n n ,求 ∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n}\lfloor \frac{n}{i} \rfloor ∑ i = 1 n ⌊ i n ⌋ ,其中 1 ≤ n ≤ 1 0 9 1\leq n\leq 10^9 1 ≤ n ≤ 1 0 9 。
显然 n i \frac{n}{i} i n 在连续的区间内值相等,故可以分成若干块再进行计算。
对于每个块,设 l l l 为该块的左边界,那么这个块的值为 k = ⌊ n l ⌋ k=\lfloor \frac{n}{l} \rfloor k = ⌊ l n ⌋ ,那么右边界 r r r 即为最大的 i i i ,且满足 i ≤ n k i\leq \frac{n}{k} i ≤ k n ,故 r = ⌊ n k ⌋ r=\lfloor \frac{n}{k} \rfloor r = ⌊ k n ⌋ ,代入 k k k 得 r = ⌊ n ⌊ n l ⌋ ⌋ r=\lfloor \frac{n}{\lfloor \frac{n}{l} \rfloor} \rfloor r = ⌊ ⌊ l n ⌋ n ⌋ 。
时间复杂度 O ( n ) \mathcal{O}(\sqrt n) O ( n ) 。
1 2 3 4 5 6 7 8 9 int mathBlock (int n) { int l=1 ,r,ans=0 ; while (l<=n){ r=n/(n/l); ans+=(n/l)*(r-l+1 ); l=r+1 ; } return ans; }
题目 :
最大公约数 最小公倍数
前置知识 :
公约数 :若 x ∣ a x\mid a x ∣ a 且 x ∣ b x\mid b x ∣ b ,则称 x x x 为 a a a 和 b b b 的公约数。
公倍数 :若 a ∣ x a\mid x a ∣ x 且 b ∣ x b\mid x b ∣ x ,则称 x x x 为 a a a 和 b b b 的公倍数。
显然最大公约数就是公约数中最大的数字,最小公倍数就是公倍数中最小的数字。
求最大公约数
欧几里得算法 :
gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\bmod b) g cd( a , b ) = g cd( b , a mod b )
设 a > b a > b a > b 且 a = b k + c a=bk+c a = bk + c ,则有 c = a m o d b c=a\bmod b c = a mod b 。
设 d ∣ a , d ∣ b d\mid a,d\mid b d ∣ a , d ∣ b ,则有:
c = a − b k c d = a d − b d k \begin{aligned}
c=a-bk\\
\frac{c}{d}=\frac{a}{d}-\frac{b}{d}k
\end{aligned}
c = a − bk d c = d a − d b k
由对 d d d 的定义可知 d ∣ c d\mid c d ∣ c ,故 gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\bmod b) g cd( a , b ) = g cd( b , a mod b ) ,得证。
时间复杂度 O ( log n ) \mathcal{O}(\log n) O ( log n ) 。
1 2 3 int gcd (int a,int b) { return b?gcd (b,a%b):a; }
更相减损术 :
gcd ( a , b ) = gcd ( a − b , b ) \gcd(a,b)=\gcd(a-b,b) g cd( a , b ) = g cd( a − b , b )
当 a = b a=b a = b 时,显然 gcd ( a , b ) = a = b \gcd(a,b)=a=b g cd( a , b ) = a = b 。
设 a ≥ b a\geq b a ≥ b ,那么 ∀ d ∣ a , d ∣ b \forall d\mid a,d\mid b ∀ d ∣ a , d ∣ b 有 d ∣ a − b d\mid a-b d ∣ a − b 。
故 a a a 和 b b b 的所有公约数都为 a − b a-b a − b 和 b b b 的公约数,gcd ( a , b ) = gcd ( a − b , b ) \gcd(a,b)=\gcd(a-b,b) g cd( a , b ) = g cd( a − b , b ) ,得证。
时间复杂度 O ( max ( a , b ) ) \mathcal{O}(\max(a,b)) O ( max ( a , b )) 。
1 2 3 4 5 6 7 int gcd (int a,int b) { while (a!=b){ if (a>b) a-=b; else b-=a; } return a; }
更相减损术优化 :
若 2 ∣ a 2\mid a 2 ∣ a 且 2 ∣ b 2\mid b 2 ∣ b ,则 gcd ( a , b ) = 2 gcd ( a 2 , b 2 ) \gcd(a,b)=2\gcd(\frac{a}{2},\frac{b}{2}) g cd( a , b ) = 2 g cd( 2 a , 2 b ) 。
反之,则若 2 ∣ a 2\mid a 2 ∣ a 且 2 ∤ b 2\nmid b 2 ∤ b ,则 gcd ( a , b ) = gcd ( a 2 , b ) \gcd(a,b)=\gcd(\frac{a}{2},b) g cd( a , b ) = g cd( 2 a , b ) 。
当 2 ∤ a , 2 ∣ b 2\nmid a,2\mid b 2 ∤ a , 2 ∣ b 时同理。
时间复杂度 O ( log n ) \mathcal{O}(\log n) O ( log n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 int gcd (int a,int b) { int aa=0 ,bb=0 ; while (!(a&1 )) a>>=1 ,++aa; while (!(b&1 )) b>>=1 ,++bb; while (1 ){ while (!(a&1 )) a>>=1 ; while (!(b&1 )) b>>=1 ; if (a==b) break ; if (a<b) swap (a,b); a-=b; } return a<<min (aa,bb); }
求最小公倍数
gcd ( a , b ) × lcm ( a , b ) = a × b \gcd(a,b)\times \operatorname{lcm}(a,b)=a\times b g cd( a , b ) × lcm ( a , b ) = a × b
由唯一分解定理 ,可使 a = p 1 c a 1 p 2 c a 2 … p k c a k , b = p 1 c b 1 p 2 c b 2 … p k c b k a=p_1^{c_{a_1}}p_2^{c_{a_2}}\dots p_k^{c_{a_k}},b=p_1^{c_{b_1}}p_2^{c_{b_2}}\dots p_k^{c_{b_k}} a = p 1 c a 1 p 2 c a 2 … p k c a k , b = p 1 c b 1 p 2 c b 2 … p k c b k 。
则最大公约数为 p 1 min ( c a 1 , c b 1 ) p 2 min ( c a 2 , c b 2 ) … p k min ( c a k , c b k ) p_1^{\min(c_{a_1},c_{b_1})}p_2^{\min(c_{a_2},c_{b_2})}\dots p_k^{\min(c_{a_k},c_{b_k})} p 1 m i n ( c a 1 , c b 1 ) p 2 m i n ( c a 2 , c b 2 ) … p k m i n ( c a k , c b k ) ,最小公倍数为 p 1 max ( c a 1 , c b 1 ) p 2 max ( c a 2 , c b 2 ) … p k max ( c a k , c b k ) p_1^{\max(c_{a_1},c_{b_1})}p_2^{\max(c_{a_2},c_{b_2})}\dots p_k^{\max(c_{a_k},c_{b_k})} p 1 m a x ( c a 1 , c b 1 ) p 2 m a x ( c a 2 , c b 2 ) … p k m a x ( c a k , c b k ) 。
由于 min ( c a , c b ) + max ( c a , c b ) = c a + c b \min(c_a,c_b)+\max(c_a,c_b)=c_a+c_b min ( c a , c b ) + max ( c a , c b ) = c a + c b ,所以 gcd ( a , b ) × lcm ( a , b ) = a × b \gcd(a,b)\times \operatorname{lcm}(a,b)=a\times b g cd( a , b ) × lcm ( a , b ) = a × b ,得证。
时间复杂度为求最大公约数的时间复杂度。
1 2 3 4 int lcm (int a,int b) { return a/gcd (a,b)*b; }
欧拉函数
前置知识 :
互质 :∀ x , y ∈ N \forall x,y\in \mathbb{N} ∀ x , y ∈ N ,若 gcd ( x , y ) = 1 \gcd(x,y)=1 g cd( x , y ) = 1 ,则称 x x x 和 y y y 互质,记作 x ⊥ y x\perp y x ⊥ y 。
积性函数 :若 x , y x,y x , y 互质且 f ( x ) × f ( y ) = f ( x y ) f(x)\times f(y)=f(xy) f ( x ) × f ( y ) = f ( x y ) ,则称函数 f f f 为积性函数。
完全积性函数 :若 ∀ x , y ∈ R \forall x,y\in \mathbb{R} ∀ x , y ∈ R ,f ( x ) × f ( y ) = f ( x y ) f(x)\times f(y)=f(xy) f ( x ) × f ( y ) = f ( x y ) ,则称 f f f 为完全积性函数。
定义 :∀ n > 1 \forall n>1 ∀ n > 1 ,∑ i = 1 n [ i ⊥ n ] \sum_{i=1}^{n}[i\perp n] ∑ i = 1 n [ i ⊥ n ] ,记作 φ ( n ) \varphi(n) φ ( n ) ,特别地,φ ( 1 ) = 1 \varphi(1)=1 φ ( 1 ) = 1 。
性质 :
若 n n n 为质数,则 φ ( n ) = n − 1 \varphi(n)=n-1 φ ( n ) = n − 1 。
∀ n > 1 \forall n>1 ∀ n > 1 ,∑ i = 1 n [ i ⊥ n ] × i = n 2 × φ ( n ) \sum_{i=1}^{n}[i\perp n]\times i=\frac{n}{2}\times \varphi(n) ∑ i = 1 n [ i ⊥ n ] × i = 2 n × φ ( n ) 。
∵ gcd ( n , x ) = gcd ( n , n − x ) \because \gcd(n,x)=\gcd(n,n-x) ∵ g cd( n , x ) = g cd( n , n − x )
∴ \therefore ∴ 若 x x x 不与 n n n 互质,则 n − x n-x n − x 也不与 n n n 互质,且 x x x 和 n − x n-x n − x 总成对出现,其平均值为 n 2 \frac{n}{2} 2 n 。
∴ \therefore ∴ 与 n n n 互质的数的平均值为 n 2 \frac{n}{2} 2 n ,而与 n n n 互质的数有 φ ( n ) \varphi(n) φ ( n ) 个,得证。
φ \varphi φ 为积性函数,即若 x , y x,y x , y 互质,则 φ ( x y ) = φ ( x ) × φ ( y ) \varphi(xy)=\varphi(x)\times \varphi(y) φ ( x y ) = φ ( x ) × φ ( y ) 。
若 n = p k n=p^k n = p k ,且 p p p 为质数,则 φ ( n ) = ( p − 1 ) × p k − 1 \varphi(n)=(p-1)\times p^{k-1} φ ( n ) = ( p − 1 ) × p k − 1 。
根据唯一分解定理 ,可知 n n n 与 p p p 的倍数都不互质,与其它数均互质。
p p p 的倍数有 p k − 1 p^{k-1} p k − 1 个(含 n n n 本身),故 φ ( n ) = p k − p k − 1 = ( p − 1 ) × p k − 1 \varphi(n)=p^k-p^{k-1}=(p-1)\times p^{k-1} φ ( n ) = p k − p k − 1 = ( p − 1 ) × p k − 1 ,得证。
若 p p p 为质数,且 p p p 为 n n n 的约数,则 φ ( n p ) = φ ( n ) × p \varphi(np)=\varphi(n)\times p φ ( n p ) = φ ( n ) × p 。
因为 p p p 为质数,所以 n p np n p 和 n n n 的质因子相同,仅 p p p 的指数不同,故(计算公式见求单个值的欧拉函数 ):
φ ( n p ) φ ( n ) = n p × ∏ i = 1 k ( 1 − 1 p i ) n × ∏ i = 1 k ( 1 − 1 p i ) = n p n = p \frac{\varphi(np)}{\varphi{(n)}}=\frac{np\times\prod_{i=1}^{k}(1-\frac{1}{p_i})}{n\times \prod_{i=1}^{k}(1-\frac{1}{p_i})}=\frac{np}{n}=p
φ ( n ) φ ( n p ) = n × ∏ i = 1 k ( 1 − p i 1 ) n p × ∏ i = 1 k ( 1 − p i 1 ) = n n p = p
所以 φ ( n p ) = φ ( n ) × p \varphi(np)=\varphi(n)\times p φ ( n p ) = φ ( n ) × p ,得证。
若 p p p 为质数且 p p p 不为 n n n 的约数,则 φ ( n p ) = φ ( n ) × ( p − 1 ) \varphi(np)=\varphi(n)\times (p-1) φ ( n p ) = φ ( n ) × ( p − 1 ) 。
因为 p p p 不为 n n n 的约数,所以 p ⊥ n p\perp n p ⊥ n 。
故 φ ( n p ) = φ ( n ) × φ ( p ) = φ ( n ) × ( p − 1 ) \varphi(np)=\varphi(n)\times \varphi(p)=\varphi(n)\times (p-1) φ ( n p ) = φ ( n ) × φ ( p ) = φ ( n ) × ( p − 1 ) ,得证。
∑ d ∣ n φ ( d ) = n \sum_{d\mid n}\varphi(d)=n ∑ d ∣ n φ ( d ) = n
设 f ( x ) = ∑ d ∣ n φ ( d ) f(x)=\sum_{d\mid n}\varphi(d) f ( x ) = ∑ d ∣ n φ ( d ) ,因为 φ \varphi φ 为积性函数,所以若 a , b a,b a , b 互质,则 f ( a b ) = ∑ d ∣ a b φ ( d ) = ( ∑ d ∣ a φ ( d ) ) × ( ∑ d ∣ b φ ( d ) ) f(ab)=\sum_{d\mid ab}\varphi(d)=(\sum_{d\mid a}\varphi(d))\times (\sum_{d\mid b}\varphi(d)) f ( ab ) = ∑ d ∣ ab φ ( d ) = ( ∑ d ∣ a φ ( d )) × ( ∑ d ∣ b φ ( d )) ,所以 f f f 为积性函数。
对于一个质因子 p k p^k p k ,f ( p k ) = ∑ d ∣ p k φ ( d ) = φ ( 1 ) + φ ( p ) + ⋯ + φ ( p k ) f(p^k)=\sum_{d\mid p^k}\varphi(d)=\varphi(1)+\varphi(p)+\dots+\varphi(p^k) f ( p k ) = ∑ d ∣ p k φ ( d ) = φ ( 1 ) + φ ( p ) + ⋯ + φ ( p k ) ,结果为等比数列求和加 1 1 1 ,结果为 p k p^k p k 。
故 f ( n ) = ∏ i = 1 k f ( p i c i ) = ∏ i = 1 k p i c i = n f(n)=\prod_{i=1}^{k}f(p_i^{c_i})=\prod_{i=1}^{k}p_i^{c_i}=n f ( n ) = ∏ i = 1 k f ( p i c i ) = ∏ i = 1 k p i c i = n ,得证。
求单个值的欧拉函数
通过唯一分解定理 ,使 n = p 1 c 1 × p 2 c 2 × ⋯ × p k c k n=p_1^{c_1}\times p_2^{c_2}\times \dots \times p_k^{c_k} n = p 1 c 1 × p 2 c 2 × ⋯ × p k c k ,则:
φ ( n ) = n × p 1 − 1 p 1 × p 2 − 1 p 2 × … p k − 1 p k = n × ∏ i = 1 k ( 1 − 1 p i ) \varphi(n)=n\times \frac{p_1-1}{p_1}\times \frac{p_2-1}{p_2}\times \dots \frac{p_k-1}{p_k}=n\times \prod_{i=1}^{k}(1-\frac{1}{p_i})
φ ( n ) = n × p 1 p 1 − 1 × p 2 p 2 − 1 × … p k p k − 1 = n × i = 1 ∏ k ( 1 − p i 1 )
对于 n n n 的所有质因子 p i p_i p i ,在 1 ∼ n 1\sim n 1 ∼ n 范围内 p i p_i p i 的倍数有 n p i \frac{n}{p_i} p i n 个。
那么对于 n n n 的两个质因子 p , q p,q p , q ,根据容斥,1 ∼ n 1\sim n 1 ∼ n 范围内含质因子 p p p 或 q q q 的数的个数为 n p + n q − n p q \frac{n}{p}+\frac{n}{q}-\frac{n}{pq} p n + q n − pq n 。
不含质因子 p p p 或 q q q 的数的个数为 n − n p − n q + n p q = n × ( 1 − 1 p − 1 q + 1 p q ) = n ( 1 − 1 p ) ( 1 − 1 q ) n-\frac{n}{p}-\frac{n}{q}+\frac{n}{pq}=n\times (1-\frac{1}{p}-\frac{1}{q}+\frac{1}{pq})=n(1-\frac{1}{p})(1-\frac{1}{q}) n − p n − q n + pq n = n × ( 1 − p 1 − q 1 + pq 1 ) = n ( 1 − p 1 ) ( 1 − q 1 ) ,将公式扩展到所有质因子 p i p_i p i 即可得证。
故在分解质因数时即可求出 φ \varphi φ ,时间复杂度 O ( n ) \mathcal O(\sqrt n) O ( n ) 。
1 2 3 4 5 6 7 8 9 10 11 int Phi (int n) { int ans=n,k=sqrt (n); F (i,2 ,k){ if (!(n%i)){ ans=ans/i*(i-1 ); while (!(n%i)) n/=i; } } if (n>1 ) ans=ans/n*(n-1 ); return ans; }
求区间内的欧拉函数
暴力 :
代码见求单个数的欧拉函数 ,时间复杂度 O ( n n ) \mathcal O(n\sqrt n) O ( n n ) 。
埃氏筛 :
时间复杂度 O ( n log n ) \mathcal O(n\log n) O ( n log n ) 。
1 2 3 4 5 6 7 8 9 10 int phi[N];void CalculatePhi (int n) { F (i,1 ,n) phi[i]=i; F (i,2 ,n){ if (phi[i]==i) for (int j=i;j<=n;j+=i) phi[j]=phi[j]/i*(i+1 ); } return ; }
线性筛 :
时间复杂度 O ( n ) \mathcal O(n) O ( n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int phi[N],v[N]; vector<int > prime;void CalculatePhi (int n) { phi[1 ]=1 ; F (i,2 ,n){ if (!v[i]) v[i]=i,phi[i]=i-1 ,prime.push_back (i); V (x,prime){ if (x>v[i]||i*x>n) break ; v[i*x]=x; phi[i*x]=phi[i]*(i%x?x-1 :x); } } return ; }
题目 :
莫比乌斯函数
定义 :若根据唯一分解定理 使正整数 n = p 1 c 1 p 2 c 2 … p k c k n=p_1^{c_1}p_2^{c_2}\dots p_k^{c_k} n = p 1 c 1 p 2 c 2 … p k c k ,则有:
μ ( n ) = { 0 , ∃ i ∈ [ 1 , k ] , c i > 1 1 , m ≡ 0 ( m o d 2 ) , ∀ i ∈ [ 1 , m ] , c i = 1 − 1 , m ≡ 1 ( m o d 2 ) , ∀ i ∈ [ 1 , m ] , c i = 1 \mu(n)=
\begin{cases}
0,\exists i \in [1,k],c_i > 1\\
1,m\equiv 0\pmod 2,\forall i \in [1,m],c_i=1\\
-1,m\equiv 1\pmod 2,\forall i \in [1,m],c_i=1
\end{cases}
μ ( n ) = ⎩ ⎨ ⎧ 0 , ∃ i ∈ [ 1 , k ] , c i > 1 1 , m ≡ 0 ( mod 2 ) , ∀ i ∈ [ 1 , m ] , c i = 1 − 1 , m ≡ 1 ( mod 2 ) , ∀ i ∈ [ 1 , m ] , c i = 1
特别地,μ ( 1 ) = 1 \mu(1)=1 μ ( 1 ) = 1 。
求单个值的莫比乌斯函数
质因数分解 :
时间复杂度 O ( n ) \mathcal{O}(\sqrt n) O ( n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int Mobius (int n) { if (n==1 ) return 1 ; int k=sqrt (n),cnt=0 ; F (i,2 ,k){ if (!(n%i)){ int ci=0 ; while (!(n/i)) n/=i,++ci; if (ci>1 ) return 0 ; ++cnt; } } if (n>1 ) ++cnt; return cnt&1 ?-1 :1 ; }
求区间内的莫比乌斯函数
埃氏筛 :
先初始化 ∀ i ∈ [ 1 , n ] , μ ( i ) = 1 \forall i\in [1,n],\mu(i)=1 ∀ i ∈ [ 1 , n ] , μ ( i ) = 1 ,显然对于质数 n n n 有 μ ( n ) = − 1 \mu(n)=-1 μ ( n ) = − 1 ,对于 n n n 的倍数,若 n 2 ∣ k n n^2\mid kn n 2 ∣ kn ,则说明出现了 c i > 1 c_i > 1 c i > 1 的情况,μ ( k n ) = 0 \mu(kn)=0 μ ( kn ) = 0 ,反之则 μ ( k n ) = − μ ( k n ) \mu(kn)=-\mu(kn) μ ( kn ) = − μ ( kn ) 。
时间复杂度 O ( n log log n ) \mathcal{O}(n\log \log n) O ( n log log n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int mu[N];bool vis[N];void Mobius (int n) { fill (mu+1 ,mu+1 +n,1 ); F (i,2 ,n){ if (vis[i]) continue ; mu[i]=-1 ; for (int j=(i<<1 );j<=n;j+=i){ v[j]=1 ; if (!((j/i)%i)) mu[i]=0 ; else mu[i]*=-1 ; } } return ; }
线性筛 :
对于质数 n n n 及每一个被遍历到的合数 n × v i n\times v_i n × v i ,若其出现 c i > 1 c_i > 1 c i > 1 ,则停止遍历,否则 μ ( n × v i ) = − μ ( n ) \mu(n\times v_i)=-\mu(n) μ ( n × v i ) = − μ ( n ) 。
时间复杂度 O ( n ) \mathcal{O}(n) O ( n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 vector<int > prime;int mu[N];bool vis[N];void Mobius (int n) { mu[1 ]=1 ; F (i,2 ,n){ if (!vis[i]) vis[i]=1 ,mu[i]=-1 ,prime.push_back (i); V (x,prime){ if (i*x>n) break ; vis[i*x]=1 ; if (!(i%x)) break ; mu[i*x]=-mu[i]; } } return ; }
同余
前置知识 :
取模的定义式:
a m o d p = { a − ⌊ a p ⌋ × p , a ≥ 0 − ( − a m o d p ) , a < 0 a\bmod p=
\begin{cases}
a-\lfloor \frac{a}{p} \rfloor \times p,a\geq 0\\
-(-a\bmod p),a<0
\end{cases}
a mod p = { a − ⌊ p a ⌋ × p , a ≥ 0 − ( − a mod p ) , a < 0
定义 :若 x m o d p = y m o d p x\bmod p=y\bmod p x mod p = y mod p ,则称 x , y x,y x , y 模 p p p 同余,记作 x ≡ y ( m o d p ) x\equiv y\pmod p x ≡ y ( mod p ) 。
性质 :
自反性 :x ≡ x ( m o d p ) x\equiv x\pmod p x ≡ x ( mod p ) 。
对称性 :若 x ≡ y ( m o d p ) x\equiv y\pmod p x ≡ y ( mod p ) ,则 y ≡ x ( m o d p ) y\equiv x\pmod p y ≡ x ( mod p ) 。
传递性 :若 x ≡ y ( m o d p ) x\equiv y\pmod p x ≡ y ( mod p ) 且 y ≡ z ( m o d p ) y\equiv z\pmod p y ≡ z ( mod p ) ,则 x ≡ z ( m o d p ) x\equiv z\pmod p x ≡ z ( mod p ) 。
同余式相加性 :若 x ≡ y ( m o d p ) x\equiv y\pmod p x ≡ y ( mod p ) 且 a ≡ b ( m o d p ) a\equiv b\pmod p a ≡ b ( mod p ) ,则 ( x ± a ) ≡ ( y ± b ) ( m o d p ) (x\pm a)\equiv (y\pm b)\pmod p ( x ± a ) ≡ ( y ± b ) ( mod p ) 。
同余式相乘性 :若 x ≡ y ( m o d p ) x\equiv y\pmod p x ≡ y ( mod p ) 且 a ≡ b ( m o d p ) a\equiv b\pmod p a ≡ b ( mod p ) ,则 a x ≡ b y ( m o d p ) ax\equiv by\pmod p a x ≡ b y ( mod p ) 。
乘法逆元
前置知识 :
费马小定理 :若 p p p 为质数且 a ⊥ p a\perp p a ⊥ p ,则 a p ≡ a ( m o d p ) a^p\equiv a\pmod p a p ≡ a ( mod p ) 。
定义 :若 a ⊥ p a\perp p a ⊥ p 且 x x x 为 a x ≡ 1 ( m o d p ) ax\equiv 1\pmod p a x ≡ 1 ( mod p ) 的解,则称 x x x 为 a a a 模 p p p 的乘法逆元,记作 a − 1 ( m o d p ) a^{-1}\pmod p a − 1 ( mod p ) 。
求单个值的乘法逆元
若 a ⊥̸ p a\not \perp p a ⊥ p ,则不存在 a a a 模 p p p 的乘法逆元。
快速幂:若 p p p 为质数,且 a ⊥ p a\perp p a ⊥ p ,根据费马小定理,可知 a a a 模 p p p 的乘法逆元为 a p − 2 m o d p a^{p-2}\bmod p a p − 2 mod p 。
由费马小定理可知 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1\pmod p a p − 1 ≡ 1 ( mod p ) 。
而我们要求 a x ≡ 1 ( m o d p ) ax\equiv 1\pmod p a x ≡ 1 ( mod p ) 的解,由传递性可得:
a x ≡ a p − 1 ( m o d p ) x ≡ a p − 2 ( m o d p ) \begin{aligned}
ax\equiv a^{p-1}\pmod p\\
x\equiv a^{p-2}\pmod p
\end{aligned}
a x ≡ a p − 1 ( mod p ) x ≡ a p − 2 ( mod p )
得证。
扩展欧几里得算法:将方程改写为 a x + p y = 1 ax+py=1 a x + p y = 1 ,使用扩展欧几里得算法 求出 x x x 即可。
题目 :
求区间内的乘法逆元
暴力+快速幂 :
仅适用于 p p p 为质数且 a ⊥ p a\perp p a ⊥ p 的情况 ,时间复杂度 O ( n log p ) \mathcal{O}(n\log p) O ( n log p ) 。
暴力+扩展欧几里得算法 :
代码见扩展欧几里得算法 ,时间复杂度 O ( n log p ) \mathcal{O}(n\log p) O ( n log p ) 。
线性递推 :
i n v i = − ⌊ p i ⌋ × i n v p m o d i m o d p inv_i=-\lfloor \frac{p}{i} \rfloor \times inv_{p\bmod i}\bmod p in v i = − ⌊ i p ⌋ × in v p mod i mod p ,特别地,i n v 1 = 1 inv_1=1 in v 1 = 1 。
设 p = k × i + r p=k\times i+r p = k × i + r ,其中 i i i 为当前的数,k k k 为 ⌊ p i ⌋ \lfloor \frac{p}{i} \rfloor ⌊ i p ⌋ ,r r r 为 p m o d i p\bmod i p mod i 。
p ≡ 0 ( m o d p ) k × i + r ≡ 0 ( m o d p ) \begin{aligned} p \equiv 0 \pmod p\\ k\times i+r \equiv 0 \pmod p \end{aligned}
p ≡ 0 ( mod p ) k × i + r ≡ 0 ( mod p )
两边同乘 i − 1 r − 1 i^{-1}r^{-1} i − 1 r − 1 得:
k × r − 1 + i − 1 ≡ 0 ( m o d p ) i − 1 ≡ − k × r − 1 ( m o d p ) i − 1 ≡ − ⌊ p i ⌋ × ( p m o d i ) − 1 ( m o d p ) \begin{aligned}
k\times r^{-1}+i^{-1} \equiv 0 \pmod p\\
i^{-1} \equiv -k\times r^{-1}\pmod p\\
i^{-1} \equiv -\lfloor \frac{p}{i} \rfloor \times {(p\bmod i)}^{-1} \pmod p
\end{aligned}
k × r − 1 + i − 1 ≡ 0 ( mod p ) i − 1 ≡ − k × r − 1 ( mod p ) i − 1 ≡ − ⌊ i p ⌋ × ( p mod i ) − 1 ( mod p )
故递推即可,得证。
时间复杂度 O ( n ) \mathcal{O}(n) O ( n ) 。
1 2 inv[1 ]=1 ;F (i,2 ,n) inv[i]=(p-p/i)*inv[p%i]%p;
题目 :
求区间内阶乘的乘法逆元
线性递推 :
f a c i n v i = f a c i n v i + 1 × ( i + 1 ) facinv_i=facinv_{i+1}\times (i+1) f a c in v i = f a c in v i + 1 × ( i + 1 ) ,特别地,f a c i n v n = i n v n ! m o d p facinv_n=inv_{n!\bmod p} f a c in v n = in v n ! mod p 。
∵ f a c i n v i + 1 = 1 ( i + 1 ) ! \because facinv_{i+1}=\frac{1}{(i+1)!} ∵ f a c in v i + 1 = ( i + 1 )! 1
∴ f a c i n v i + 1 × ( i + 1 ) = 1 i ! = f a c i n v i \therefore facinv_{i+1}\times (i+1)=\frac{1}{i!}=facinv_i ∴ f a c in v i + 1 × ( i + 1 ) = i ! 1 = f a c in v i
得证。
时间复杂度 O ( n ) \mathcal{O}(n) O ( n ) 。
欧拉定理
前置知识 :
同余类 :∀ a ∈ [ 0 , m − 1 ] \forall a\in[0,m-1] ∀ a ∈ [ 0 , m − 1 ] ,集合 { a + k m } ( k ∈ Z ) \{a+km\}(k\in \mathbb{Z}) { a + km } ( k ∈ Z ) 的所有数模 m m m 同余,余数均为 a a a ,则称该集合为一个模 m m m 的同余类,记为 a ‾ \overline{a} a 。
完全剩余系 :m m m 个模 m m m 的同余类 i ‾ ( i ∈ [ 0 , m − 1 ] ) \overline{i} (i\in[0,m-1]) i ( i ∈ [ 0 , m − 1 ]) 所构成的集合称为完全剩余系。
简化剩余系 :φ ( m ) \varphi(m) φ ( m ) 个与 m m m 互质的数的同余类所构成的集合称为简化剩余系。
费马小定理 :见乘法逆元 。
定义 :若 a ⊥ p a\perp p a ⊥ p ,则 a φ ( p ) ≡ 1 ( m o d p ) a^{\varphi(p)}\equiv 1\pmod p a φ ( p ) ≡ 1 ( mod p ) 。
扩展欧拉定理
a b ≡ { a b m o d φ ( p ) , a ⊥ p a b , a ⊥̸ p , b < φ ( p ) a b m o d φ ( p ) + φ ( p ) , a ⊥̸ p , b ≥ φ ( p ) ( m o d p ) a^b\equiv
\begin{cases}
a^{b\bmod \varphi(p)},a\perp p\\
a^b,a\not \perp p,b<\varphi(p)\\
a^{b\bmod \varphi(p)+\varphi(p)},a\not \perp p,b\geq \varphi(p)
\end{cases}
\pmod p
a b ≡ ⎩ ⎨ ⎧ a b mod φ ( p ) , a ⊥ p a b , a ⊥ p , b < φ ( p ) a b mod φ ( p ) + φ ( p ) , a ⊥ p , b ≥ φ ( p ) ( mod p )
题目 :
扩展欧几里得算法
前置知识 :
欧几里得算法 :见求最大公约数 。
裴蜀定理(Bézout 定理) :∀ a , b ∈ Z , ∃ x , y ∈ Z , a x + b y = gcd ( a , b ) \forall a,b\in \mathbb{Z},\exists x,y\in \mathbb{Z},ax+by=\gcd(a,b) ∀ a , b ∈ Z , ∃ x , y ∈ Z , a x + b y = g cd( a , b ) 。
在欧几里得算法的最后一步,即 b = 0 b=0 b = 0 时,显然存在 x = 1 , y = 0 x=1,y=0 x = 1 , y = 0 使 a × 1 + 0 × 0 = gcd ( a , 0 ) a\times 1+0\times 0=\gcd(a,0) a × 1 + 0 × 0 = g cd( a , 0 ) 。
考虑当 b > 0 b>0 b > 0 时,gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\bmod b) g cd( a , b ) = g cd( b , a mod b ) ,设存在一对整数 x , y x,y x , y 使得 gcd ( b , a m o d b ) = b x + ( a m o d b ) y \gcd(b,a\bmod b)=bx+(a\bmod b)y g cd( b , a mod b ) = b x + ( a mod b ) y 。
由取模的定义式,可转化 b x + ( a m o d b ) y = b x + ( a − b ⌊ a b ⌋ ) y = a y + b ( x − ⌊ a b ⌋ y ) bx+(a\bmod b)y=bx+(a-b\lfloor \frac{a}{b} \rfloor)y=ay+b(x-\lfloor \frac{a}{b} \rfloor y) b x + ( a mod b ) y = b x + ( a − b ⌊ b a ⌋) y = a y + b ( x − ⌊ b a ⌋ y ) 。
故当 x ′ = y , y ′ = x − ⌊ a b ⌋ y x^{\prime}=y,y^{\prime}=x-\lfloor \frac{a}{b} \rfloor y x ′ = y , y ′ = x − ⌊ b a ⌋ y 时,有 a x ′ + b y ′ = gcd ( a , b ) ax^{\prime}+by^{\prime}=\gcd(a,b) a x ′ + b y ′ = g cd( a , b ) ,对递归过程使用数学归纳法即可得证。
对于求 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) a x + b y = g cd( a , b ) 中 x , y x,y x , y 的值,由裴蜀定理的证明中可知仅需要在欧几里得算法中保存 x , y x,y x , y 即可。
1 2 3 4 5 6 7 8 9 10 11 int exgcd (int a,int b,int &x,int &y) { if (!b){ x=1 ,y=0 ; return a; } int d=exgcd (b,a%b,x,y); int z=x; x=y; y=z-y*(a/b); return d; }
题目 :
中国剩余定理
前置知识 :
乘法逆元 :见乘法逆元 。
若 p 1 , p 2 , … , p n p_1,p_2,\dots,p_n p 1 , p 2 , … , p n 两两互质 ,求解方程组:
{ x ≡ a 1 ( m o d p 1 ) x ≡ a 2 ( m o d p 2 ) ⋮ x ≡ a n ( m o d p n ) \begin{cases}
x\equiv a_1\pmod {p_1}\\
x\equiv a_2\pmod {p_2}\\
\vdots \\
x\equiv a_n\pmod {p_n}
\end{cases}
⎩ ⎨ ⎧ x ≡ a 1 ( mod p 1 ) x ≡ a 2 ( mod p 2 ) ⋮ x ≡ a n ( mod p n )
设 m = ∏ i = 1 n p i m=\prod_{i=1}^{n}{p_i} m = ∏ i = 1 n p i ,M i = m p i M_i=\frac{m}{p_i} M i = p i m ,t i t_i t i 为 M i M_i M i 模 p i p_i p i 的乘法逆元,则 x = ∑ i = 1 n a i M i t i m o d m x=\sum_{i=1}^{n}{a_iM_it_i}\bmod m x = ∑ i = 1 n a i M i t i mod m 。
∵ M i \because M_i ∵ M i 为除 p i p_i p i 外所有模数的倍数且 p 1 , p 2 , … , p n p_1,p_2,\dots,p_n p 1 , p 2 , … , p n 两两互质。
∴ ∀ k ≠ i , a k M k t k ≡ 0 ( m o d p k ) \therefore \forall k\neq i,a_kM_kt_k\equiv 0\pmod {p_k} ∴ ∀ k = i , a k M k t k ≡ 0 ( mod p k )
∵ t i ≡ ( M i ) − 1 ( m o d p i ) \because t_i\equiv(M_i)^{-1}\pmod {p_i} ∵ t i ≡ ( M i ) − 1 ( mod p i )
∴ a i M i t i ≡ a i ( m o d p i ) \therefore a_iM_it_i\equiv a_i\pmod {p_i} ∴ a i M i t i ≡ a i ( mod p i )
由同余式相加性且 m = ∏ i = 1 n p i m=\prod_{i=1}^{n}{p_i} m = ∏ i = 1 n p i 可知 x x x 在展开之后即为 ∑ i = 1 n a i M i t i m o d m \sum_{i=1}^{n}{a_iM_it_i}\bmod m ∑ i = 1 n a i M i t i mod m ,得证。
时间复杂度 O ( n log p ) \mathcal{O}(n\log p) O ( n log p ) 。
1 2 3 4 5 6 7 8 int CRT (int n) { F (i,1 ,n){ exgcd (M/p[i],p[i],x,y); x=(x%p[i]+p[i])%p[i]; ans+=x*a[i]*(M/p[i]),ans%=M; } return ans; }
题目 :
扩展中国剩余定理
前置知识 :
扩展欧几里得算法 :见扩展欧几里得算法 。
若 p 1 , p 2 , … , p n p_1,p_2,\dots,p_n p 1 , p 2 , … , p n 不保证两两互质,则上述结论不成立,需要另外一种解法。
考虑 n = 2 n=2 n = 2 的情况,可转化为不定方程 x = k p 1 + a 1 = b p 2 + a 2 , k , b ∈ Z x=kp_1+a_1=bp_2+a_2,k,b\in \mathbb{Z} x = k p 1 + a 1 = b p 2 + a 2 , k , b ∈ Z ,则有 k p 1 − b p 2 = a 2 − a 1 kp_1-bp_2=a_2-a_1 k p 1 − b p 2 = a 2 − a 1 。
若 a 2 − a 1 ∤ gcd ( p 1 , p 2 ) a_2-a_1 \nmid \gcd(p_1,p_2) a 2 − a 1 ∤ g cd( p 1 , p 2 ) ,则无解,反之可用扩展欧几里得算法 求出一组解 ( k , b ) (k,b) ( k , b ) 。
则 x ≡ k p 1 + a 1 ( m o d lcm ( p 1 , p 2 ) ) x\equiv kp_1+a_1\pmod {\operatorname{lcm} (p_1,p_2)} x ≡ k p 1 + a 1 ( mod lcm ( p 1 , p 2 )) 。
扩展到 n ≠ 2 n\neq 2 n = 2 的情况,仅需要依次求解即可。
时间复杂度 O ( n log n ) \mathcal{O}(n\log n) O ( n log n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 int exCRT (int n) { int ret=a[1 ],cur=p[1 ],x,y; F (i,2 ,n){ int gcd=exgcd (cur,p[i],x,y),c=((a[i]-ret)%p[i]+p[i])%p[i]; if (c%gcd) return -1 ; x=quick_mul (x,c/gcd,p[i]/gcd); ret+=x*cur; cur=cur/gcd*p[i]; ret=(ret%cur+cur)%cur; } return (ret%cur+cur)%cur; }
题目 :
组合
加法原理 乘法原理
加法原理 (分类):一个问题有 n n n 类 方法,每个类别有 a i a_i a i 个不同的方法,那么解决此问题有 a 1 + a 2 + ⋯ + a n a_1+a_2+\dots+a_n a 1 + a 2 + ⋯ + a n 个方法。
乘法原理 (分布):一个问题有 n n n 个 方法,每个方法有 a i a_i a i 个不同的方式,那么解决此问题的方式个数为 a 1 × a 2 × ⋯ × a n a_1\times a_2\times \dots \times a_n a 1 × a 2 × ⋯ × a n 。
容斥原理
当 n = 2 n=2 n = 2 时,∣ A ∪ B ∣ = ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣ |A\cup B|=|A|+|B|-|A\cap B| ∣ A ∪ B ∣ = ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣
当 n = 3 n=3 n = 3 时,∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ A ∩ B ∩ C ∣ |A\cup B\cup C|=|A|+|B|+|C|-|A\cap B|-|A\cap C|-|B\cap C|+|A\cap B\cap C| ∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ A ∩ B ∩ C ∣
通项式 :∣ ⋃ i = 1 n A i ∣ = ∑ ∅ ≠ J = ⊆ { 1 , 2 , … , n } ( − 1 ) ∣ J ∣ − 1 ∣ ⋂ j ∈ J A j ∣ |\bigcup_{i=1}^{n}A_i|=\sum_{\varnothing \neq J=\subseteq\{1,2,\dots,n\}}(-1)^{|J|-1}|\bigcap_{j\in J}A_j| ∣ ⋃ i = 1 n A i ∣ = ∑ ∅ = J =⊆ { 1 , 2 , … , n } ( − 1 ) ∣ J ∣ − 1 ∣ ⋂ j ∈ J A j ∣
德摩根定律
A ∪ B ‾ = A ‾ ∩ B ‾ \overline{A\cup B}=\overline{A}\cap \overline{B} A ∪ B = A ∩ B ,A ∩ B ‾ = A ‾ ∪ B ‾ \overline{A\cap B}=\overline{A}\cup \overline{B} A ∩ B = A ∪ B
简记 :交之补等于补之并,并之补等于补之交。
推论 :∣ ⋂ i = 1 n A i ‾ ∣ = ∑ ∅ ≠ J ⊆ { 1 , 2 , … , n } ( − 1 ) ∣ J ∣ ∣ ⋂ j ∈ J A j ∣ |\bigcap_{i=1}^{n}\overline{A_i}|=\sum_{\varnothing \neq J\subseteq \{1,2,\dots,n\}}(-1)^{|J|}|\bigcap_{j\in J} A_j| ∣ ⋂ i = 1 n A i ∣ = ∑ ∅ = J ⊆ { 1 , 2 , … , n } ( − 1 ) ∣ J ∣ ∣ ⋂ j ∈ J A j ∣
∣ ⋃ i = 1 n A i ∣ = ∑ ∅ ≠ J = ⊆ { 1 , 2 , … , n } ( − 1 ) ∣ J ∣ − 1 ∣ ⋂ j ∈ J A j ∣ ∣ ⋂ i = 1 n A i ‾ ∣ = ∑ ∅ ≠ J ⊆ { 1 , 2 , … , n } ( − 1 ) ∣ J ∣ ∣ ⋂ j ∈ J A j ∣ ∣ ⋂ i = 1 n A i ∣ = ∑ ∅ ≠ J ⊆ { 1 , 2 , … , n } ( − 1 ) ∣ J ∣ ∣ ⋂ j ∈ J A j ‾ ∣ \begin{aligned}
|\bigcup_{i=1}^{n}A_i|=\sum_{\varnothing \neq J=\subseteq\{1,2,\dots,n\}}(-1)^{|J|-1}|\bigcap_{j\in J}A_j|\\
|\bigcap_{i=1}^{n}\overline{A_i}|=\sum_{\varnothing \neq J\subseteq \{1,2,\dots,n\}}(-1)^{|J|}|\bigcap_{j\in J} A_j|\\
|\bigcap_{i=1}^{n}{A_i}|=\sum_{\varnothing \neq J\subseteq \{1,2,\dots,n\}}(-1)^{|J|}|\bigcap_{j\in J} \overline{A_j}|
\end{aligned}
∣ i = 1 ⋃ n A i ∣ = ∅ = J =⊆ { 1 , 2 , … , n } ∑ ( − 1 ) ∣ J ∣ − 1 ∣ j ∈ J ⋂ A j ∣ ∣ i = 1 ⋂ n A i ∣ = ∅ = J ⊆ { 1 , 2 , … , n } ∑ ( − 1 ) ∣ J ∣ ∣ j ∈ J ⋂ A j ∣ ∣ i = 1 ⋂ n A i ∣ = ∅ = J ⊆ { 1 , 2 , … , n } ∑ ( − 1 ) ∣ J ∣ ∣ j ∈ J ⋂ A j ∣
排列数 组合数
排列数 :A n k = n ! ( n − k ) ! A_{n}^{k}=\frac{n!}{(n-k)!} A n k = ( n − k )! n !
组合数 :C n k = ( n k ) = A n k k ! = n ! ( n − k ) ! k ! = n × ( n − 1 ) × ⋯ × ( n − k + 1 ) k ! = ∏ i = 0 k − 1 ( n − i ) k ! C_{n}^{k}=\binom{n}{k}=\frac{A_{n}^{k}}{k!}=\frac{n!}{(n-k)!k!}=\frac{n\times(n-1)\times \dots \times (n-k+1)}{k!}=\frac{\prod_{i=0}^{k-1}{(n-i)}}{k!} C n k = ( k n ) = k ! A n k = ( n − k )! k ! n ! = k ! n × ( n − 1 ) × ⋯ × ( n − k + 1 ) = k ! ∏ i = 0 k − 1 ( n − i )
特别地,若 k > n k>n k > n 则 A n k = C n k = 0 A_{n}^{k}=C_{n}^{k}=0 A n k = C n k = 0 。
性质 :
C n 0 = 1 C_{n}^{0}=1 C n 0 = 1 ,C n 1 = n C_{n}^{1}=n C n 1 = n ,C n 2 = n ( n − 1 ) 2 C_{n}^{2}=\frac{n(n-1)}{2} C n 2 = 2 n ( n − 1 )
C n k = C n n − k C_{n}^{k}=C_{n}^{n-k} C n k = C n n − k
C n k = C n − 1 k + C n − 1 k − 1 C_{n}^{k}=C_{n-1}^{k}+C_{n-1}^{k-1} C n k = C n − 1 k + C n − 1 k − 1
∑ i = 0 n C n i = 2 n \sum_{i=0}^{n}C_{n}^{i}=2^n ∑ i = 0 n C n i = 2 n
求组合数
暴力 :
1 2 3 4 5 6 int C (int n,int k,int p) { int a=1 ,b=1 ; F (i,0 ,k-1 ) a*=(n-i); F (i,1 ,k) b*=i; return (a/b)%p; }
时间复杂度 O ( T n ) \mathcal{O}(Tn) O ( T n ) ,但适用性极差(易爆 long long
)。
递推预处理 :
C i , j = { 1 , j = 0 C i − 1 , j + C i − 1 , j − 1 , otherwise C_{i,j}=
\begin{cases}
1,j=0\\
C_{i-1,j}+C_{i-1,j-1},\text{otherwise}
\end{cases}
C i , j = { 1 , j = 0 C i − 1 , j + C i − 1 , j − 1 , otherwise
由性质 3 3 3 得证。
1 2 3 4 5 6 7 void InitC (int n,int p) { F (i,0 ,n){ C[i][0 ]=1 ; F (j,1 ,i) C[i][j]=(C[i-1 ][j]+C[i-1 ][j-1 ])%p; } return ; }
时间复杂度 O ( n 2 + T ) \mathcal{O}(n^2+T) O ( n 2 + T ) 。
预处理阶乘+逆元 :
这里使用了快速幂求逆元。
1 2 3 4 int C (int n,int k,int p) { if (!k) return 1 ; return (fac[n]*ksm (fac[n-k],p-2 ,p)%p*ksm (fac[k],p-2 ,p)%p)%p; }
时间复杂度 O ( n + T log p ) \mathcal{O}(n+T\log p) O ( n + T log p ) 。
卢卡斯定理 :
见卢卡斯定理 ,仅限 p p p 为质数时适用 ,时间复杂度 O ( p + T × log n ) \mathcal{O}(p+T\times \log n) O ( p + T × log n ) 。
扩展卢卡斯定理 :
当 p p p 不为质数时也适用,时间复杂度 O ( p + T log p ) \mathcal{O}(p+T\log p) O ( p + T log p ) 。
二项式定理
( x + y ) n = C n 0 x n y 0 + C n 1 x n − 1 y 1 + ⋯ + C n n x 0 y n = ∑ i = 0 n C n i x n − i y i (x+y)^{n}=C_{n}^{0}x^ny^0+C_{n}^{1}x^{n-1}y^{1}+\dots+C_{n}^{n}x^0y^n=\sum_{i=0}^{n}C_{n}^{i}x^{n-i}y^i
( x + y ) n = C n 0 x n y 0 + C n 1 x n − 1 y 1 + ⋯ + C n n x 0 y n = i = 0 ∑ n C n i x n − i y i
对于每一个 ( x + y ) (x+y) ( x + y ) ,显然要么选 x x x ,要么选 y y y 。
若有 k k k 个 ( x + y ) (x+y) ( x + y ) 选择 y y y ,则有 n − k n-k n − k 个选择 x x x ,由于要选取 k k k 个 ( x + y ) (x+y) ( x + y ) ,故系数为 C n k C_{n}^{k} C n k 。
因为 k k k 为分类,所以利用加法原理,得证。
计数技巧
等价替代
对于某些计数题,正面解决可能会很困难,这时可以用一些方法将问题转化为另一种更为容易计算的问题。
捆绑法
若要求某些物品相邻 ,则可将所需相邻的物品看做一个整体,然后计算排列,再分别计算每个整体内的排列相乘。
例题 :有 ABCDE \text{ABCDE} ABCDE 五种物品,其中要求 AB \text{AB} AB 相邻,CD \text{CD} CD 相邻,求排列方案数。
可先将 AB \text{AB} AB 和 CD \text{CD} CD 看作一个整体,然后对剩下的 3 3 3 个物品进行排列,有 A 3 3 = 6 A_{3}^{3}=6 A 3 3 = 6 种排列方案。
然后再计算各个整体内的排列,A 2 2 = 2 A_{2}^{2}=2 A 2 2 = 2 种。
故共有 2 × A 2 2 × A 3 3 = 24 2\times A_{2}^{2}\times A_{3}^{3}=24 2 × A 2 2 × A 3 3 = 24 种排列方案。
插空法
若要求某些物品两两不相邻 ,则可先将其它的物品排好,然后再从空当中插入,分别计算排列后相乘。
例题 :有 ABCDEFG \text{ABCDEFG} ABCDEFG 其中物品,其中要求 ABC \text{ABC} ABC 两两不相邻,求排列方案数。
先对其它 4 4 4 种物品进行排列,有 A 4 4 = 24 A_{4}^{4}=24 A 4 4 = 24 种方案。
然后将剩下 3 3 3 种物品插入到其中的 5 5 5 个空当中,有 A 5 3 = 60 A_{5}^{3}=60 A 5 3 = 60 种方案,故共有 A 4 4 × A 5 3 = 1440 A_{4}^{4}\times A_{5}^{3}=1440 A 4 4 × A 5 3 = 1440 种排列方案。
隔板法
至少分配问题 和不定方程整数解问题 可转化为关于插板的组合问题。
例题 1 1 1 :将 n n n 个物品分给 k k k 个人,要求每个人至少被分配到一个,求方案数。
将 n n n 件物品排成一行,中间有 k − 1 k-1 k − 1 个隔板,表示每个人分到的部分,而 k − 1 k-1 k − 1 个隔板只能插入到 n − 1 n-1 n − 1 个空当中,故方案数为 C n − 1 k − 1 C_{n-1}^{k-1} C n − 1 k − 1 。
例题 2 2 2 :将例题 1 1 1 的限制改为“允许有人被分配到 0 0 0 个”,求方案数。
可将题意抽象为数学模型,求方程 ∑ i = 1 k x i = n \sum_{i=1}^{k}x_i=n ∑ i = 1 k x i = n 的解,其中 x i ≥ 1 x_i\geq 1 x i ≥ 1 。
若改限制为 x ≥ 0 x\geq 0 x ≥ 0 ,则设 y i = x i + 1 y_i=x_i+1 y i = x i + 1 ,转化为 ∑ i = 1 k = n + k \sum_{i=1}^{k}=n+k ∑ i = 1 k = n + k 。
再结合上题的解,即可求出方案数为 C n + k − 1 k − 1 C_{n+k-1}^{k-1} C n + k − 1 k − 1 。
改变计数目标
对于某些计数题,直接解决可能会很困难,可以用减法原理或容斥原理等内容转化为容易求的问题。
改变枚举顺序
对于某些计数题,直接枚举只能拿到暴力分,可以改变枚举顺序使其更容易计算。
例题 :求 ∑ i = 1 n ∑ j = 1 n max ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{n}\max(i,j) ∑ i = 1 n ∑ j = 1 n max ( i , j ) 。
∑ i = 1 n ∑ j = 1 n max ( i , j ) = ∑ k = 1 n k ∑ i = 1 n ∑ j = 1 n [ max ( i , j ) = k ] = ∑ k = 1 n k ( 2 k − 1 ) = 2 ∑ k = 1 n k 2 − ( n + 1 ) n 2 = 4 n 3 + 3 n 2 − n 6 \begin{aligned}
\sum_{i=1}^{n}\sum_{j=1}^{n}\max(i,j)
&=\sum_{k=1}^{n}k\sum_{i=1}^{n}\sum_{j=1}^{n}[\max(i,j)=k]\\
&=\sum_{k=1}^{n}k(2k-1)\\
&=2\sum_{k=1}^{n} k^2 -\frac{(n+1)n}{2}\\
&=\frac{4n^3+3n^2-n}{6}
\end{aligned}
i = 1 ∑ n j = 1 ∑ n max ( i , j ) = k = 1 ∑ n k i = 1 ∑ n j = 1 ∑ n [ max ( i , j ) = k ] = k = 1 ∑ n k ( 2 k − 1 ) = 2 k = 1 ∑ n k 2 − 2 ( n + 1 ) n = 6 4 n 3 + 3 n 2 − n
多重集的排列组合数
多重集 :指包含重复元素的广义集合。
多重集的排列数
设 S = { n 1 a 1 , n 2 a 2 , … , n k a k } S=\{n_1a_1,n_2a_2,\dots,n_ka_k\} S = { n 1 a 1 , n 2 a 2 , … , n k a k } 为多重集,则 S S S 的全排列个数为
( ∑ i = 1 k i ) ! ∏ i = 1 k n i ! \frac{(\sum_{i=1}^{k} i)!}{\prod_{i=1}^{k}n_i!}
∏ i = 1 k n i ! ( ∑ i = 1 k i )!
多重集的组合数
设 S = { n 1 a 1 , n 2 a 2 , … , n k a k } S=\{n_1a_1,n_2a_2,\dots,n_ka_k\} S = { n 1 a 1 , n 2 a 2 , … , n k a k } 为多重集,从 S S S 中取出 r ( r ≤ min ( n i ) ) r(r\leq \min(n_i)) r ( r ≤ min ( n i )) 个元素组成一个多重集,不考虑元素顺序,产生不同的多重集的数量为
C k + r − 1 k − 1 C_{k+r-1}^{k-1}
C k + r − 1 k − 1
设对于每一个 a i a_i a i 选取 x i x_i x i 个,则问题可转化为 ∑ i = 1 k x i = r ( x i ≥ 0 ) \sum_{i=1}^{k}x_i=r(x_i\geq 0) ∑ i = 1 k x i = r ( x i ≥ 0 ) 的不定方程。
用隔板法求解即可。
卢卡斯定理
模数 p p p 必须为质数 。
C n m m o d p = C n p m p × C n m o d p m m o d p m o d p C_{n}^{m}\bmod p=C_{\frac{n}{p}}^{\frac{m}{p}}\times C_{n\bmod p}^{m\bmod p}\bmod p
C n m mod p = C p n p m × C n mod p m mod p mod p
其中对于左半部分进行递归,右半部分直接进行计算,因为 n m o d p , m m o d p ∈ [ 0 , p − 1 ] n\bmod p,m\bmod p\in [0,p-1] n mod p , m mod p ∈ [ 0 , p − 1 ] 。
时间复杂度 O ( p + T × log n ) \mathcal{O}(p+T\times \log n) O ( p + T × log n ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int fac[N],facinv[N];void Init (int n,int p) { fac[0 ]=1 ; F (i,1 ,n) fac[i]=fac[i-1 ]*i,fac[i]%=p; facinv[n]=ksm (fac[n],p-2 ,p); FJ (i,n-1 ,0 ) facinv[i]=facinv[i+1 ]*(i+1 ),facinv[i]%=p; return ; }int C (int n,int m,int p) { if (m>n) return 0 ; return ((fac[n]*facinv[m])%p*facinv[n-m])%p; }int Lucas (int n,int m,int p) { if (!m||n==m) return 1 ; return (Lucas (n/p,m/p,p)*C (n%p,m%p,p))%p; }int Solve (int n,int m,int p) { Init (p-1 ,p); return Lucas (n,m,p); }
卡特兰数
定义 :一种常出现于各种计数问题的数列,记作 H n H_n H n ,特别地,H 0 = H 1 = 1 H_0=H_1=1 H 0 = H 1 = 1 。
卡特兰数列 :
n n n
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
… \dots …
H n H_n H n
1 1 1
1 1 1
2 2 2
5 5 5
14 14 14
42 42 42
132 132 132
⋯ \cdots ⋯
常见题型
n n n 个左括号和 n n n 个右括号组成的合法括号序列的数量?H n H_n H n 。
入栈序列为 1 , 2 , … , n 1,2,\dots,n 1 , 2 , … , n 的合法出栈序列数量?H n H_n H n 。
n n n 个节点构成的不同的二叉树的数量?H n H_n H n 。
只能向上或向右走,能从 ( 0 , 0 ) (0,0) ( 0 , 0 ) 走到 ( n , n ) (n,n) ( n , n ) 且不接触 直线 y = x y=x y = x 的路线的数量?2 H n − 1 2H_{n-1} 2 H n − 1 。
只能向上或向右走,能从 ( 0 , 0 ) (0,0) ( 0 , 0 ) 走到 ( n , n ) (n,n) ( n , n ) 且不穿过 直线 y = x y=x y = x 的路线的数量?H n + 1 H_{n+1} H n + 1 。
求卡特兰数
以下所有公式均有 i ≥ 2 i\geq 2 i ≥ 2 。
递推 :
H i = H i − 1 ( 4 i − 2 ) i + 1 H_i=\frac{H_{i-1}(4i-2)}{i+1}
H i = i + 1 H i − 1 ( 4 i − 2 )
组合通式 :
H i = C 2 i i i + 1 H_i=\frac{C_{2i}^{i}}{i+1}
H i = i + 1 C 2 i i
H i = C 2 i i − C 2 i i − 1 H_i=C_{2i}^{i}-C_{2i}^{i-1}
H i = C 2 i i − C 2 i i − 1
H i = ∑ j = 1 i H j − 1 H i − j H_i=\sum_{j=1}^{i}H_{j-1} H_{i-j}
H i = j = 1 ∑ i H j − 1 H i − j