「算法学习」斯特林数和斯特林反演
第二类斯特林数
第二类斯特林数:将 \(n\) 个不同元素划分为 \(k\) 个不区分的集合的方案数。表示为 \(n \brace k\) 或 \(S(n,k)\)。
递推式:\({n \brace k}={n-1\brace k-1}+k{n-1\brace k}\)。边界是 \({n \brace 0}=[n=0]\)。
通项:令划分成 \(i\) 个可为零的集合的方案数为 \(g_i\),没有空集的方案数为 \(f_i\),则 \(g_i=\sum_{j=0}^i\binom i jf_j\),反演一下 \(f_i=\sum_{j=1}^i(-1)^{i-j}\binom i jg_j=\sum_{j=1}^i(-1)^{i-j}\binom i jn^j\)。由于 \(n \brace k\) 要求集合之间不区分,所以 \({n \brace k}=\sum_{i=1}^k\frac {(-1)^{k-i}\ \ i^n}{i!(k-i)!}\)。(注意这里是 \(i^n\) 而不是 \(n^i\))
同一行第二类斯特林数:用上面的通项卷积即可,时间复杂度 \(\mathcal {O}(n\log_2 n)\)。
同一列第二类斯特林数:
第一类斯特林数
第一类斯特林数:将 \(n\) 个不同元素划分为 \(k\) 个轮换的方案数。表示为 \(n\brack k\) 或 \(s(n,k)\)。
递推式:\({n\brack k}={n-1\brack k-1}+(n-1){n-1\brack k}\),边界是 \({n\brack 0}=[n=0]\)。
通项:目前第一类斯特林数没有实用的通项公式。
同一行第一类斯特林数:类似第二类斯特林数,我们构造同行第一类斯特林数的生成函数,即 \(F_n(x)=\sum_{i=0}^n {n\brack i}x^i\)。根据递推公式,\(F_n(x)=(n-1)F_{n-1}(x)+xF_{n-1}(x)=\prod_{i=0}^{n-1}(x+i)=\frac {(x+n-1)!} {(x-1)!}\)。这其实是 \(x\) 的 \(n\) 次阶乘幂,记作 \(x^{\overline n}\)。这个东西可以分治乘 \(\mathcal {O}(n\log^2 n)\),也可以用上升幂相关做法 \(\mathcal {O}(n\log n)\) 求出。
同一列第一类斯特林数:
斯特林反演
可以先回顾一下二项式反演,二项式反演的核心式子是 \(\sum_{k=j}^i (-1)^{k-j}\binom i k \binom k j=\sum_{k=j}^i (-1)^{k-j}\binom i j \binom {i-j} {k-j}=\binom i j \sum_{k=0}^{i-j}(-1)^{k}\binom {i-j} {k}=\binom i j \sum_{k=0}^{i-j}(-1)^{k}\binom {i-j} {k}=\binom i j (1-1)^{i-j}=[i=j]\)。
\(a_{ij}:=\binom i j\),\(b_{ij}:=(-1)^{i-j}\binom i j\),\(c_{ij}:=\sum_{k=0}^n a_{ik}b_{kj}=\sum_{k=j}^i (-1)^{k-j}\binom i k \binom k j=[i=j]\)。
即 \(AB=C=I\),所以 \(AF=G \Rightarrow F=BG\)。
所以 \(g(n)=\sum_{i=0}^n a_{ni}f(i)=\sum_{i=0}^n \binom n i f(i)\Rightarrow f(n)=\sum_{i=0}^n b_{ni}g(i)=\sum_{i=0}^n (-1)^{n-i} \binom n i g(i)\)。
同理,斯特林反演也有这样一个核心式子:
\([i=j]=\sum_{k=j}^i(-1)^{i-k}{i\brack k}{k \brace j}\)。
\([i=j]=\sum_{k=j}^i(-1)^{i-k}{i\brace k}{k \brack j}\)。
所以,斯特林反演的形式和二项式反演基本一致:
\(g(n)=\sum_{i=0}^n {n \brace i}f(i)\Rightarrow f(n)=\sum_{i=0}^n(-1)^{n-i} {n \brack i}g(i)\)。
\(g(n)=\sum_{i=0}^n {n \brack i}f(i)\Rightarrow f(n)=\sum_{i=0}^n(-1)^{n-i} {n \brace i}g(i)\)。
考虑证明这两个核心式子:
上升幂与普通幂,下降幂与普通幂
上升幂与普通幂的相互转化:我们记上升阶乘幂 \(x^{\overline n}=\prod_{i=0}^{n-1}(x+i)=\frac {(x+n-1)!} {(x-1)!}\)。
则可以利用下面的恒等式将上升幂转化为普通幂:\(x^{\overline{n}}=\sum_{k=0}^n{n\brack k}x^k\)。(第一斯特林数的生成函数)
如果将普通幂转化为上升幂,其实反演一下就好了:\(x^n=\sum_{k=0}^n (-1)^{n-k} {n\brace k}x^{\overline k}\)。
同理,将 \(x\) 换成 \(-x\),\(x^{n}=\sum_{k=0}^n{n\brace k}x^{\underline{k}}\)。
反演一下,\(x^{\underline{n}}=\sum_{k=0}^n(-1)^{n-k}{n\brack k}x^{k}\)。
多项式下降阶乘幂表示与多项式点值表示的关系
其实就是稍微推推式子化成卷积。
例题
CountTables
令 \(f_i\) 为所有行不相同的方案数,\(g_i\) 为所有行和列都不相同的方案数。
\(f_i=(C^i)^{\underline m}=\sum_{j=0}^n {i \brace j}g_j\)。
所以 \(g_i=\sum_{j=0}^n (-1)^{n-j} {i \brack j}f_j=\sum_{j=0}^n (-1)^{n-j} {i \brack j}(C^i)^{\underline m}\)。答案即为 \(g_n\)。
「BZOJ4671」异或图
令 \(f_i\) 为至少有 \(i\) 个连通块的方案数,\(g_i\) 为恰好有 \(i\) 个连通块的方案数。
\(f_i=\sum_{j=i}^n {j \brace i}g_j \Rightarrow g_i=\sum_{j=i}^n (-1)^{j-i} {j \brack i} f_j\)。
现在要求 \(f_i\)。发现可以枚举拆分的情况,连通块之间的边异或和为 \(1\),简单高斯消元判有无解求自由元即可。
时间复杂度:\(\mathcal {O}(Bell(n)n^4 s/\omega)\)。
[国家集训队] Crash 的文明世界
套路幂和转下降幂。
\(\sum_{j=1}^n dist(i,j)^k=\sum_{j=1}^n \sum_{u=0}^k {k \brace u}\binom {dist(i,j)} {u}*u!\)。
由于 \(\mathcal {O}(nk)\) 可过,设 \(f(i,j)\) 为 \(i\) 子树内 \(\sum \binom {dist(i,u)} {j}\)。这个东西算二次递推即可。然后再做一次换根即可。
CF932E Team Work
\(\mathcal {Way\ 1}\):用上面那个 trick:幂转下降幂。然后组合数计算即可。
\(\mathcal {Way\ 2}\):