计数相关

狄利克雷卷积式
\(\displaystyle [n=1]=\sum_{d|n} μ(d)\)

\(n\)个点的树(有标号)

\(n^{n-2}\)

\(n\)个点的环套树(有标号)

\(\displaystyle \frac {\sum_{k=3}^{n} n^{n-k} \prod_{l=1}^{k-1} (n-l) } {2}\)

杜教筛

构造函数\(g(i)\)
\(\displaystyle g(1)s(n)=\sum_{i=1}^n (f*g)(i) - \sum_{i=2}^n g(i)s(n/i)\)
数论分块计算,记忆化,复杂度\(O(n^{2/3})\)

一种扩展杜教筛法

\[\sum_{i=1}^n (f*g)(i) = \sum_{ij\le n}f(i)g(j) \]

\(N\)个点的环套树(有标号)证明

先选出一个环,再决定环的顺序,再把整个环跟其他点串起来,需要用到 \(\text{prufer}\) 序列有关的芝士 。

\[F(n)=\sum_{i=3}^N {N\choose i} \frac{(i-1)!}{2} * i * N^{N-i-1} \\ =\frac{(N-1)!}{2}\sum_{i=0}^{N-3}\frac{N^i}{i!} \]

\(N\)个点的环套树(有标号)计数

考虑EGF,设环套树的EGF为F(x),有根树的EGF为G(x)。
枚举环多大,然后把若干个有根树挂在环上:

\[F(x)=\sum_{k>2} \frac{(k-1)!}{2} \frac{G^k(x)}{k!} \\ = \frac{1}{2}\sum_{k>2}\frac{G^k(x)}{k} \]

求导以后求逆解决,积分回来即可:

\[F'(x) = \frac{1}{2} \sum_{k>2} \frac{k·G^{k-1}(x)·G'(x)}{k} = \frac{1}{2} G'(x)G^2(x) \frac{1}{1-G(x)} \]

多项式牛顿迭代形式

设有一方程 \(G(F(x))=0 \pmod {x^n}\)
假如对于这个 \(n\) 我们求得 $$G(f(x))=0 \pmod {x^{\left \lceil \frac{n}{2} \right \rceil}}$$
那么有:$$F(x)=f(x)-\dfrac{ G(f(x)) }{ G'(f(x)) } \pmod {x^n}$$
边界是 \(n=1\),倍增复杂度是 \(O(n\log n)\)
多项式求逆、多项式开根和多项式 \(\exp\) 均使用此方法推导。

有标号DAG

只考虑不一定连通的;
根据上述即 \(f(n)=\sum_{i=1}^n (-1)^{i+1} {n\choose i}f(n-i)2^{i(n-i)}\),推一下可以多项式求逆。

有标号二分图

设连通的二分图egf是\(f(x)\),然后定义黑白图表示黑白染色的二分图,那么连通的黑白图egf是\(2f(x)\)
那么由组合意义普通黑白图的egf是 \(F(x)=\exp 2f(x)\)
\(F(x)\) 易于求出,设 \(h_i\) 表示 \(i\) 个点黑白图的个数,可以枚举有几个涂黑,\(h_i=\sum_{j+k=i} {i\choose j} 2^{jk}\)
通过单次多项式乘法可以得到 \(F(x)\),然后整个都能算了。复杂度 \(O(n\log n)\)
如果只要求普通二分图,可以考虑多项式开根,复杂度 \(O(n\log n)\)

常系数线性递推

首先如果对矩阵的特征多项式取模可得

\[A^n=\sum_{i=0}^{k-1} r_iA^i \]

现在求的是

\[Ans=PA^n[0]=\sum_{i=0}^{k-1} r_iPA^i[0] \]

发现初始向量乘 \(i\) 个转移矩阵相当于左移 \(i\) 位,那么有 \(Ans=\sum_{i=0}^{k-1} r_iP_i\)

现在计算 \(r_i\) 特征多项式为 \(B(x)=x^k-a_1x^{k-1}-\cdots-a_{k-1}x-a_k\)
倍增做多项式取模,常数是快速幂的 \(1\over 2\)

伯努利数预处理幂和多项式

很多筛法题要求幂和然后 \(k\le 300\) 然后可以 \(O(k^2)\) 预处理幂和多项式以后很方便做。

设B数的生成函数是:

\[B(x)={x\over e^x-1}=\sum_{i=0}^\infty B_ix^i \]

可以推出幂和多项式 $$A_k(x)=k! \sum_{j=1}^{k+1} {B_{k+1-j}\over j!}x^j$$

然后显然最高次项是 \(x^{k+1}\),代码如下

for(int i = 0; i <= n; i++) {
	for(int j = i + 1; j <= n; j++)
		B[j] = (B[j] - 1ll * B[i] * ifac[j - i + 1]) % mod;
	(B[i] += mod) %= mod;
}
++B[1];
v[0] = {0, 1};
for(int i = 1; i <= n; i++)
{
	v[i].resize(i + 2);
	for(int j = 1; j <= i + 1; j++)
		v[i][j] = 1ll * B[i + 1 - j] * fac[i] % mod * ifac[j] % mod;
	for(auto &x : v[i])
		printf("%d ", x);
	puts("");
}
posted @ 2019-02-06 21:23  bestwyj  阅读(464)  评论(0)    收藏  举报