Cayley 定理

节点个数为 \(n\) 的无根标号树的个数为 \(n^{n−2}\) 。

这个结论在很多计数类题目中出现,要证明它首先需要了解 \(\text{Prufer}\) 序列的相关内容。接下来给出证明。

证明:

每一棵树都可以转换为一个 \(\text{Prufer}\) 序列。

根据定义,每一个节点在 \(\text{Prufer}\) 序列中出现的次数等于该节点度数减一,即 \(d_i–1\)。整个 \(\text{Prufer}\) 序列的长度为 \(∑_id_i–1=2(n−1)–n=n–2\) 。

无根树的形态可以与 \(\text{Prufer}\) 序列一一对应,所以无根树的个数也等于 \(\text{Prufer}\) 序列的个数。故个数为 \(n−2\) 。

扩展 Cayley 定理 1

\(n\) 个标号节点形成一个有 \(s\) 颗树的森林且给定的 \(s\) 个点没有两个点属于同一颗树的方案数个数为 \(sn^{n-s-1}\) 。

证明:记其为 \(F(n,s)\)(\(1\le s\le n\)),其中被钦定的 \(s\) 个不在同一棵树的点的标号是 \([n-s+1,n]\) 。枚举 \(n\) 的度数 \(j\) ,则得到以下递推式:

\[F(n,s)=\sum_{j=0}^{n-s}\binom{n-s}{j}F(n-1,s-1+j)
\]

下面使用数学归纳法来证明 \(F(n,s)=sn^{n-s-1}\) :

\(n=1\) 时显然成立。

当 \(n>1\) 时,若 \(n-1\) 成立(即对于 \(1\le k\le n-1\),\(F(n-1,k)=k(n-1)^{n-1-k}\) ,则有:

\[F(n,s)=\sum_{j=0}^{n-s}\binom{n-s}{j}(s-1+j)(n-1)^{n-s-j-1}
\\
=\frac{1}{n-1}\sum_{j=0}^{n-s}\binom{n-s}{j}(s-1)(n-1)^{n-s-j}+\frac{1}{n-1}\sum_{j=0}^{n-s}\binom{n-s}{j}j(n-1)^{n-s-j}
\\
=\frac{s-1}{n-1}\sum_{j=0}^{n-s}\binom{n-s}{j}(n-1)^{n-s-j}+\frac{n-s}{n-1}\sum_{j=0}^{n-s}\binom{n-s-1}{j-1}(n-1)^{n-s-j}
\\
=\frac{s-1}{n-1}n^{n-s}+\frac{n-s}{n-1}n^{n-s-1}=\frac{sn-s}{n-1}n^{n-s-1}=sn^{n-s-1}
\]

得证。

组合解释:

把给定的 \(s\) 个点看成被钦定的根结点,先当作没给定,然后再除以 \(\Large\binom{n}{s}\) 。加一个虚点 \(0\),把所有根连成它的儿子,变成 \(n+1\) 个点。钦定 \(0\) 的度数为 \(s\) 的树的个数。

\(\text{prufer}\) 序列的长度是 \(n-1\),钦定其中有 \(s-1\) 个是 \(0\),剩下的是 \(1,2,\cdots , n\) 。则方案数是 \({\large\binom{n-1}{s-1}}\times n^{n-s}\) 。然后再除以 \(\Large\binom{n}{s}\) ,得到 \(sn^{n-s-1}\) 。

扩展 Cayley 定理 2

对于一棵 \(n\) 个节点有标号无根树,已经被若干条边分成了大小分别为的若干连通块 \(a_1,a_2,\cdots, a_m\),连成一棵树的方案数为 \(\prod a_i \times n^{m-2}\) 。

用 \(\text{Matrix-Tree}\) 定理证明:

将每一个连通块压在一起考虑,此时有连通块 \(a_i,a_j\) 之间的边数即为 \(a_i\cdot a_j\) 。

那么有矩阵如下:

\[\left(\begin{array}{ccccc} a_1(n-a_1)& -a_1a_2 & -a_1a_3 & \cdots & -a_1a_m\\ -a_2a_1& a_2(n-a_2) & -a_2a_3 & \cdots & -a_2a_m \\ & & \ddots & & \\ -a_{m-1}a_1 & -a_{m-1} a_2 & -a_{m-1}a_3 & \cdots & -a_{m-1}a_m\\ -a_{m}a_1 & -a_{m} a_2 & -a_{m}a_3 & \cdots & a_m(n-a_m)\end{array}\right)
\]

去掉最后一行,最后一列,得到:

\[\left(\begin{array}{ccccc} a_1(n-a_1)& -a_1a_2 & -a_1a_3 & \cdots & -a_1a_{m-1}\\ -a_2a_1& a_2(n-a_2) & -a_2a_3 & \cdots & -a_2a_{m-1} \\ & & \ddots & & \\ -a_{m-1}a_1 & -a_{m-1} a_2 & -a_{m-1}a_3 & \cdots & a_{m-1}(n-a_{m-1})\end{array}\right)
\]

接下来要算其行列式,首先化简矩阵,第 \(i (i>1)\) 行减去第 \(i-1\) 行 \(\times \dfrac{a_i}{a_{i-1}}\) 。

得到新的矩阵:

\[\left(\begin{array}{cccccc} a_1(n-a_1)& -a_1a_2 & -a_1a_3 & \cdots & -a_1a_{m-2} & -a_1a_{m-1}\\ -a_2n& a_2n & 0 & \cdots & 0& 0 \\ & & & \ddots & & \\ 0 & 0 & 0 & \cdots & -a_{m-1}n & a_{m-1}n\end{array}\right)
\]

此时,除了第一行以外的每一行,只在 \(i-1,i\) 处有值,这样的特殊矩阵,带入行列式的表达式

\[\displaystyle \det(A)=\sum_{\text{p is a permutation}} (-1)^{N(p)} \prod A_{i,p_i}
\]

有值的 \(p\) 只有 \(n\) 个,分成两类:

  1. \(p_i=i,N(p)=0\),\(\prod A_{i,p_i}=(n-a_1)n^{m-2} \prod_{i<m}\limits a_i\)

  2. \(p_1=q(q>1),p_j=\left\{\begin{aligned} j-1 && 2\leq j\leq q\\ j && q<j\end{aligned}\right.\)

\[\prod A_{i,p_i}=(-1)^{q-1} (-n)^{q} n^{m-1-q}a_q \prod_{i<m}\limits a_i=-n^{m-2} a_q\prod_{i<m}\limits a_i
\]

则:

\[\det=(n-a_1-a_2-\cdots-a_{m-1})n^{m-2} \prod_{i<m}\limits a_i=a_mn^{m-2} \prod_{i<m}\limits a_i=n^{m-2} \prod a_i
\]

即方案数为 \(n^{m-2} \prod a_i\) 。

CF1109D Sasha and Interesting Fact from Graph Theory

给定参数 \(n,m,a,b\) ,你现在要构造一颗 \(n\) 个点树,树边的权值可以赋为 \([1,m]\) 中的一个整数。

求有多少种构造树的方法,使得节点 \(a\) 与节点 \(b\) 在树上的最短路径恰好为 \(m\) ,答案对 \(10^9+7\) 取模。

然后枚举 \(a\) 和 \(b\) 之间的边数 \(e\)。首先,除了 \(a\) 和 \(b\) 两个点以外有 \(n-2\) 个点,从中选出 \(e-1\) 个排成 \(a\) 到 \(b\) 中间的点,方案数是 \((n-2) ^ {\underline{e-1}}\) 。

\(a\) 到 \(b\) 权值和为 \(m\) 且每个边权都在 \([1,m]\) 中,所以是在 \(a\) 到 \(b\) 之间插板,方案数是 \(\binom{m-1}{e-1}\) 。

剩下的 \(n-e-1\) 个数的权值可以任取,则方案数是 \(m^{n-e-1}\) 。因为是这条链上 \(e+1\) 个点都挂一棵树,所以再乘上 \(F(n,e+1)\) 。

答案即为:

\[\sum_{e=1}^{n-1} (n-2) ^ {\underline{e-1}}\times \binom{m-1}{e-1}\times m^{n-e-1}\times F(n,e+1)
\]
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n, m, a, b;
const int md = 1e9 + 7;
int fac[1000005], inv[1000005], F[1000005];
inline int pwr(int x, int y) {
int res = 1; y = (y + md - 1) % (md - 1);
while (y) {
if (y & 1) res = 1ll * res * x % md;
x = 1ll * x * x % md; y >>= 1;
}
return res;
}
inline void init() {
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for (int i = 2; i <= 1e6; i++) fac[i] = 1ll * fac[i - 1] * i % md;
for (int i = 2; i <= 1e6; i++) inv[i] = 1ll * (md - md / i) * inv[md % i] % md;
for (int i = 2; i <= 1e6; i++) inv[i] = 1ll * inv[i] * inv[i - 1] % md;
for (int i = 1; i <= 1e6; i++) F[i] = 1ll * i * pwr(n, n - i - 1) % md;
}
inline int C(int x, int y) {
if (x < y) return 0;
return 1ll * fac[x] * inv[y] % md * inv[x - y] % md;
}
int main() {
scanf("%d%d%d%d", &n, &m, &a, &b);
init();
int res = 0;
for (int i = 1; i < n; i++) {
int tmp = 1ll * fac[n - 2] * inv[n - 1 - i] % md * C(m - 1, i - 1) % md * pwr(m, n - i - 1) % md * F[i + 1] % md;
res = (res + tmp) % md;
}
printf("%d\n", res); return 0;
}

「NOI2022模拟赛czx2」图

给定一张图 \(G = (V = {1, 2, · · · , n}, E = {(u_1, v_1), (u_2, v_2), · · · , (u_m, v_m)})\)。

先将其复制 \(k\) 份,得到一张 \(nk\) 个点,\(mk\) 条边的图 \(G′\),设其补图为 \(H\) ,求 \(H\) 的生成树数量 \(\pmod P\)。

考虑进行容斥,强制出现 \(G\) 中的若干条边,对于剩下的部分,由 \(\text{Ex-Cayley}\) 定理可知,答案为 \(∏ s_i· (nk)^{c−2}\) ,其中 \(s_i\) 表示每一个连通块的大小,\(c\) 表示连通块的数量。

若能求出 \(G\) 中生成 \(i\) 个连通块的答案,添加 \((nk)^i\) 的系数后做 \(k\) 次幂,就也能求出 \(G′\) 的总答案。

考虑使用 \(\text{Matrix-Tree}\) 定理求解 \(G′\) 的答案,设:\(f_c =∑ ∏ s_i· (nk)^c\)

添加 \(0\) 号点,\(0\) 向每一个节点连接一条权为 \(x\) 的边,求出生成树。

则每一个连通块有 \(s_i\) 种向根节点连边的方案,且每一个连通块会使得最终的总权值 \(×x\) 。

即求出的行列式为一个多项式 \(f(x)\),\([x^c]f(x) = f_c\) ,观察可以发现,我们并不需要知道整个多项式,只需要知道 \(∑(−nk)^if_i\) ,即 \(f(−nk)\) 即可。

再考虑模数不是质数的情况,高斯消元可以采用辗转相除法,复杂度依然为 \(O(n^4)\) ,而算法 \(2\) 和算法 \(3\) 在计算的最后均需要添加系数 \((nk)^{−2}\),而 \(nk\) 可能不存在逆元。

容易发现 \(f(x)\) 并不存在常数项,因此可以将 \(i\to 0\) 的边权设为 \(1\) ,而 \(0\to i\) 的边权仍为 \(x\) 。

再将根节点设为 \(0\) 以外的点即可求解出 \(\frac f x(−nk)\),最后添加 \((nk)^{k−2}\) 作为系数即可(\(k = 1\) 时需要特判)。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n, m, k, md;
inline int pwr(int x, int y) {
int res = 1;
while (y) {
if (y & 1)
res = 1ll * res * x % md;
x = 1ll * x * x % md;
y >>= 1;
}
return res;
}
struct mat {
int a[105][105];
inline int* operator[](int t) { return a[t]; }
inline int det() {
int res = 1;
for (int i = 0; i < n; i++) {
int loc = i;
for (int j = n - 1; j >= i; j--) if (a[j][i]) loc = j;
if (loc != i) swap(a[i], a[loc]), res = -res;
if (!a[i][i]) return 0;
for (int j = i + 1; j < n; j++) {
while (a[j][i]) {
int tmp = a[i][i] / a[j][i];
for (int t = i; t < n; t++) a[i][t] = (a[i][t] - 1ll * tmp * a[j][t]) % md;
swap(a[i], a[j]); res = -res;
}
}
}
for (int i = 0; i < n; i++) res = 1ll * res * a[i][i] % md;
return (res + md) % md;
}
} mp;
int main() {
freopen("graph.in", "r", stdin);
freopen("graph.out", "w", stdout);
scanf("%d%d%d%d", &n, &m, &k, &md);
if (k == 1) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) mp[i][j] = n - 1;
else mp[i][j] = -1;
}
}
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
mp[x - 1][x - 1]--; mp[y - 1][y - 1]--;
mp[x - 1][y - 1] = mp[y - 1][x - 1] = 0;
}
n--;
printf("%d\n", mp.det());
} else {
for (int i = 1; i <= m; i++) {
int x, y; scanf("%d%d", &x, &y);
mp[x][x]++; mp[y][y]++;
mp[x][y] = mp[y][x] = -1;
}
int nk = 1ll * n * k % md;
for (int i = 1; i <= n; i++) {
mp[0][0] = (mp[0][0] - 1) % md;
mp[i][i] = (mp[i][i] - nk) % md;
mp[i][0] = (mp[i][0] + nk) % md;
mp[0][i] = (mp[0][i] + 1) % md;
}
int res = pwr(mp.det() * (n & 1 ? md - 1ll : 1ll) % md, k);
printf("%lld\n", 1ll * res * pwr(nk, k - 2) % md);
} return 0;
}

Cayley 定理与扩展 Cayley 定理的更多相关文章

  1. Lucas定理和扩展Lucas定理

    1.Lucas定理 首先给出式子:\(C_n^m\%p = C_{\lfloor\frac{n}{p}\rfloor}^{\lfloor\frac{m}{p}\rfloor} * C_{n\%p}^{ ...

  2. 2015 ICL, Finals, Div. 1 Ceizenpok’s formula(组合数取模,扩展lucas定理)

    J. Ceizenpok’s formula time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  3. 卢卡斯定理&扩展卢卡斯定理

    卢卡斯定理 求\(C_m^n~mod~p\) 设\(m={a_0}^{p_0}+{a_1}^{p_1}+\cdots+{a_k}^{p_k},n={b_0}^{p_0}+{b_1}^{p_1}+\cd ...

  4. 【learning】 扩展lucas定理

    首先说下啥是lucas定理: $\binom n m \equiv \binom {n\%P} {m\%P} \times \binom{n/P}{m/P} \pmod P$ 借助这个定理,求$\bi ...

  5. BZOJ - 2142 礼物 (扩展Lucas定理)

    扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...

  6. [bzoj2142]礼物(扩展lucas定理+中国剩余定理)

    题意:n件礼物,送给m个人,每人的礼物数确定,求方案数. 解题关键:由于模数不是质数,所以由唯一分解定理, $\bmod  = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_ ...

  7. Ceizenpok’s formula Gym - 100633J 扩展Lucas定理 + 中国剩余定理

    http://codeforces.com/gym/100633/problem/J 其实这个解法不难学的,不需要太多的数学.但是证明的话,我可能给不了严格的证明.可以看看这篇文章 http://ww ...

  8. bzoj2142 礼物——扩展卢卡斯定理

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ...

  9. 【知识总结】扩展卢卡斯定理(exLucas)

    扩展卢卡斯定理用于求如下式子(其中\(p\)不一定是质数): \[C_n^m\ mod\ p\] 我们将这个问题由总体到局部地分为三个层次解决. 层次一:原问题 首先对\(p\)进行质因数分解: \[ ...

随机推荐

  1. 查找SQL SERVER卡顿语句

    SELECT [session_id], [blocking_session_id] AS '正在阻塞其他会话的会话ID', DB_NAME([database_id]) AS '数据库名称', [r ...

  2. 邮件html页编写指南

    前言 写过邮件的html一般都用table来布局,为什么呢?原因是大多数的邮件客户端(比如Outlook和Gmail),会过滤经过多次的邮件编写实践及度娘的指导,我发现,编写自制兼容outlook与f ...

  3. XGBoost文本分类,多分类、二分类、10-Fold(K-Fold)

    做机器学习的时候经常用到XGB,简单记录一下 K折交叉验证也是模型常用的优化方法.一起记录... K折交叉验证:类似三个臭皮匠,顶个诸葛亮.我的理解是,就是用民主投票的方式,选取票数最高的那个当结果. ...

  4. shiro550反序列学习

    Shiro550 shiro550和fastjson作为攻防演练的利器,前面学习了fastjson的相关利用和回显,本篇主要来学习一下shiro550的漏洞原理. 1.漏洞原因 在 Shiro < ...

  5. IOC简介 -Bean的作用域 创建对象

    创建对象 创建对象时默认使用无参构造器,无论对象在容器中后续是否被使用, 都会先实例化对象 . (婚介网站,里面人都是先存在的,到时直接牵手就行) 也可以使用以下方法,使用有参构造器来创建对象 根据参 ...

  6. 用python实现matlib的 生成高斯模糊核

    最近在做一个关于模糊图片恢复的数学建模,遇到了一个大问题,特记录一下. 在matlib中有  PSF = fspecial('motion', LEN, THETA);  来生成模糊核函数,但在pyt ...

  7. JZ008和大于等于target的最短数组

    title: 长度最小的子数组 题目描述 题目链接:长度最小的子数组.剑指offer008 解题思路 简单滑动窗口题目,需要知道: 窗口左指针移动条件:窗口内总和 ≥ target 即可以不断移动窗口 ...

  8. Java操作Hadoop、Map、Reduce合成

    原始数据: Map阶段 1.每次读一行数据, 2.拆分每行数据, 3.每个单词碰到一次写个1 <0, "hello tom"> <10, "hello ...

  9. 『现学现忘』Git基础 — 23、Git中的撤销操作

    目录 1.撤销操作说明 2.撤销工作区中文件的修改 3.撤销暂存区中文件的修改 4.总结 1.撤销操作说明 我们在使用Git版本管理时,往往需要撤销某些操作.比如说我们想将某个修改后的文件撤销到上一个 ...

  10. drools的简单入门案例

    一.背景 最近在学习规则引擎drools,此处简单记录一下drools的入门案例. 二.为什么要学习drools 假设我们存在如下场景: 在我们到商店购买衣服的时候,经常会发生这样的事情,购买1件不打 ...