寫在前面:這篇文章進一步介紹一些基礎數學知識,包括組合的進一步研究、特殊的數等。
容斥原理
復習一下最基礎的容斥:
Min-Max 容斥
kth Min-Max 容斥
一般化的容斥
那么
容斥系數
對於最簡單的組合容斥\(ans = \sum_{\text{some set s1, s2, ..., sk}} ans(s1 \cap s2 \cap ... \cap sk))f(|s1 \cap s2 \cap ... \cap sk|)\)
要滿足假設一個點在\(n\)個集合里,\(\sum_{i = 1}^n {n \choose i} f(i) = [n > 0]\)。
最后一步根據題意可以改,\(O(n^2)\)可以求容斥系數\(f\)
還有一種斯特林形式,十分類似,即\(ans = \sum_{x 是一個划分} ans(x) f(|x|)\)
還有一些其他的trick,比如把一個划分的容斥系數定為各部分size的容斥系數乘起來。
假設一個點被選中\(n\)次,容斥系數應該滿足\(\sum_{i = 1}^n{n\choose i}f(i) =n\bmod 2\),答案就是\(\sum_{S} { \left\lfloor\dfrac{n}{lcm(S)} \right\rfloor f(|S|)}\)
斯特林數
貝爾數 Bell
定義\(B_n\)表示把\(n\)個不同元素划分成若干集合的方案數。很多時候在復雜度分析上會用到他。
Bell數的前幾項是:
\(1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, 115975\)
遞推公式:枚舉\(k\)表示多少元素不與最后一個元素在同一個集合。
和第二類斯特林數的關系:\(B_n\)等於第二類斯特林數第\(n\)行之和。
二項式反演
二項式反演常用於解決恰好取若干個的問題
形式1
證明:
注意一下,\((-1)^{i+j}=(-1)^{i-j}\)
形式2
證明:
P.S. 感謝why隊長完成形式2證明。
實際上也有基於容斥的證明,大概思想就是把容斥的式子和f,g函數對應,以后有時間可以來證,問題不大。
接下來看一個例題:Gym 101933K:King's Colors
題意:用恰好k種顏色塗n個結點的樹,相鄰結點不能同色,問方案數\(\mod 10^9+7\)。\(2\leq k\leq n \leq 2500\)。
題解:
如果是用\(k\)種顏色隨便塗,答案就是\(k(k-1)^{n-1}\),根是隨意的,其他結點不能和父親顏色一樣。
既然\(\leq k\)很好求,那令\(g(k)\)表示用\(1...k\)這些顏色的塗法,\(g(k)=k(k-1)^{n-1}\)
同時:(我們認為\(f(0)=1\))
直接二項式反演:
預處理組合數就做完了,時間復雜度\(O(k\log n)\)。(樹結構讀都不用讀)
#include <algorithm>
#include <cstdio>
using namespace std;
const int mo = 1e9 + 7;
const int N = 2510;
int n, k, fac[N] = {1}, fav[N];
int qpow(int a, int b) {
int ans = 1;
for(; b >= 1; b >>= 1, a = 1ll * a * a % mo)
if(b & 1) ans = 1ll * ans * a % mo;
return ans;
}
int C(int x, int y) {
return x < y ? 0 : 1ll * fac[x] * fav[y] % mo * fav[x - y] % mo;
}
int main() {
scanf("%d%d", &n, &k);
for(int i = 1; i <= k; i ++) fac[i] = 1ll * fac[i - 1] * i % mo;
fav[k] = qpow(fac[k], mo - 2);
for(int i = k; i >= 1; i --) fav[i - 1] = 1ll * fav[i] * i % mo;
int ans = 0;
for(int i = 0; i <= k; i ++) {
int t = 1ll * i * qpow(i - 1, n - 1) % mo * C(k, i) % mo;
if((k + i) & 1) (ans += mo - t) %= mo;
else (ans += t) %= mo;
}
printf("%d\n", ans);
return 0;
}