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. 转载:Linux图形界面知识(介绍X、X11、GNOME、Xorg、KDE等之间的关系)

    转载 http://blog.csdn.net/zhangxinrun/article/details/7332049Linux初学者经常分不清楚linux和X之间,X和Xfree86之间,X和KDE ...

  2. “如何实现集中管理、灵活高效的CI/CD”在线研讨会精彩内容分享

      "如何实现集中管理.灵活高效的CI/CD"在线研讨会精彩片段分享 片段主讲人:李培(西瓜刀) 大家好,我是李培.前面听文老师讲DevOps,包括CI/CD 的一些理论,也是挺有 ...

  3. Hadoop(四)C#操作Hbase

    Hbase Hbase是一种NoSql模式的数据库,采用了列式存储.而采用了列存储天然具备以下优势: 可只查涉及的列,且列可作为索引,相对高效 针对某一列的聚合及其方便 同一列的数据类型一致,方便压缩 ...

  4. Django学习——Django测试环境搭建、单表查询关键字、神奇的双下划线查询(范围查询)、图书管理系统表设计、外键字段操作、跨表查询理论、基于对象的跨表查询、基于双下划线的跨表查询

    Django测试环境搭建 ps: 1.pycharm连接数据库都需要提前下载对应的驱动 2.自带的sqlite3对日期格式数据不敏感 如果后续业务需要使用日期辅助筛选数据那么不推荐使用sqlite3 ...

  5. MybatisCodeHelperPro简单使用

    1.idea安装 2.连接mysql 3.创建实体等关联类 ,选择数据库表右键选择如图 4配置 生成后的 5简单应用 可以直接生成xml 总结:非常的方便快捷.

  6. 使用Visual Studio 2022开发前端

    前端开发环境多数基于Node.js,好处不多说了.但与使用Visual Studio开发的后端Asp.Net Core项目一起调试,却不是很方便,所以试着在Visual Studio 2022中开发前 ...

  7. Spring按业务模块输出日志到不同的文件

    一.背景 在我们开发的过程中,可能存在如下情况: 1.有些时候我们需要调用第三方的接口,一般情况下,调用接口,我们都会记录请求的入参和响应的.如果我们自己系统的日志和第三方的日志混合到一个日志文件中, ...

  8. (Bezier)贝塞尔曲在路径规划的运用

    前言 之前被安排了活,一个局部区域机器运动控制的工作,大致是一个机器位于一个极限区域时候,机器要进入一个特殊的机制,使得机器可以安全的走出来.其中用到了bezier曲线进行优化路径,今天写一下,正好也 ...

  9. MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中

    union 会删除重复数据 union all 不会删除重复数据 select * from ( select *,'a' as kind from tablea where name is not ...

  10. 234. Palindrome Linked List - LeetCode

    Question 234. Palindrome Linked List Solution 题目大意:给一个链表,判断是该链表中的元素组成的串是否回文 思路:遍历链表添加到一个list中,再遍历lis ...