菜就多练练

文章探讨了如何使用容斥原理直接证明矩阵树定理,并将其推广到无向图和有向图的内向/外向树计算,以及基环树的计数问题。还涉及到了欧拉图的欧拉回路及其计数方法,介绍了BEST定理的应用背景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Part 1

众所周知矩阵树定理可以用著名的 Cauthy-Binet 定理来证明,但是我们其实可以直接根据容斥来证明,并且拓展性更好。

对于无向图的情况,可以将问题转化为删去第 i i i个点,其他每个点指定一条出边(有向的,可以指向 i i i),使得不出现环的方案数。

再看矩阵行列式的定义: det ( A ) = ( − 1 ) σ ( p ) ∑ A i , p i \text{det}(A)=(-1)^{\sigma(p)}\sum A_{i,p_i} det(A)=(1)σ(p)Ai,pi,考虑 i i i p i p_i pi连边,这样形成了若干个置换环,对于 p i = i p_i=i pi=i的点可以任意选择出边,剩下的出边已经钦定了,方案数就是 G i , p i G_{i,p_i} Gi,pi(邻接矩阵)。最后考虑容斥系数,首先每个 p i ≠ i p_i\ne i pi=i的点会贡献 − 1 -1 1的系数,其次每个环对逆序对的贡献为环的大小 − 1 -1 1,因此恰好为 ( − 1 ) c y c (-1)^{cyc} (1)cyc

所以答案是 det(D-G) \text{det(D-G)} det(D-G)

对于有向图的情况,可以发现内向树的答案还是 det(D-G) \text{det(D-G)} det(D-G) G G G表示有向图的邻接矩阵),外向树反一下就好了。

Part 2

能不能推广到基环树(森林)计数?

引子:

求每个点恰有一条出边,且形成的简单环的环长都是奇数的方案的权值和,其中方案的权值定义为 2 k 2^k 2k k k k表示形成的简单环的数量。 n ≤ 500 n\le 500 n500

因为是基环树,所以有 n n n条边,因此矩阵的大小应该为 n n n

考虑容斥,钦定一些点形成置换环,剩下的点任选出边,容斥系数为 ( − 1 ) c y c (-1)^{cyc} (1)cyc,其中 c y c cyc cyc表示偶环的数量。这样,对于存在偶环的方案贡献为 0 0 0,对于只存在奇环的方案贡献为 2 k 2^k 2k

不难发现这就是 det(D+G) \text{det(D+G)} det(D+G)

Part 3

能不能反着用?

引子:

定义 n × n n\times n n×n的矩阵 A A A为: A i , i = c i A_{i,i}=c_i Ai,i=ci A p i , i = a i A_{p_i,i}=a_i Api,i=ai A i , p i = b i A_{i,p_i}=b_i Ai,pi=bi i ≥ 2 , p i < i i\ge 2,p_i<i i2,pi<i),其余位置均为 x x x。求 det(A) \text{det(A)} det(A) n ≤ 1 0 6 n\le 10^6 n106

考虑 x = 0 x=0 x=0怎么做。将 i i i p i p_i pi连边,则构成一颗树。根据行列式的定义,对于每个 i i i,只能指向父亲,自己或者儿子。本质上就是拆分成若干个大小为 1 1 1或者 2 2 2的置换环,可以直接树 D P DP DP

对于 x > 0 x>0 x>0的情况,考虑构造 X = ( x ) n × n X=(x)_{n\times n} X=(x)n×n Y = A − X Y=A-X Y=AX,则:

det(X+Y) = ∑ σ ∏ i = 1 n ( x + Y i , σ i ) \text{det(X+Y)}=\sum_{\sigma}\prod_{i=1}^n(x+Y_{i,\sigma_i}) det(X+Y)=σi=1n(x+Yi,σi)

如果我们选择了两项 x x x(记作下标 q 1 , q 2 q_1,q_2 q1,q2),那么必然存在另一个 σ \sigma σ(即交换 q 1 , q 2 q_1,q_2 q1,q2),使得权值相同但符号相反。

因此 x x x至多有一项,即至多存在一条非树边,这等价于选两个点 u , v u,v u,v,然后把 u , v u,v u,v路径上的点删去(单独形成一个置换环),剩下的点形成若干个大小不超过 2 2 2的环。可以用树形 D P DP DP解决,不再赘述。

Part 4

为啥我之前没学懂BEST定理

对于一个有向欧拉图,从起点 s s s出发的欧拉回路数目是(认为所有边均不同):

F ( s ) = T s ( G ) × ( d s ! ) × ∏ u ≠ s ( d u − 1 ) ! F(s)=T_s(G)\times (d_s!)\times \prod_{u\ne s}(d_u-1)! F(s)=Ts(G)×(ds!)×u=s(du1)!

其中 T s ( G ) T_s(G) Ts(G)表示以 s s s为根的内向生成树个数, d u d_u du表示出边数目。

其中 T s ( G ) T_s(G) Ts(G)枚举的是最后从 u u u离开的边(即树边),剩下的边遍历方式任意。

证明很简单。我们只需要证明每次删掉一条边后图弱联通即可,注意到每次删掉一条树边时整颗子树一定都被删掉了(否则一定不是最后一条出边),得证。

对于整张图,对应的欧拉回路数目是

F ( s ) = T s ( G ) × ∏ ( d u − 1 ) ! F(s)=T_s(G)\times \prod(d_u-1)! F(s)=Ts(G)×(du1)!

因为 s s s在欧拉回路出现了 d s d_s ds次,而从任意一个 s s s出发都能得到不同的欧拉回路,除掉 d s d_s ds即可。

因此还可以证明对于任意 s s s T s ( G ) T_s(G) Ts(G)都是相同的。

引子:[ABC336G] 16 Integers

考虑建立点 ( i , j , k ) (i,j,k) (i,j,k),然后 ( i , j , k ) (i,j,k) (i,j,k) ( j , k , l ) (j,k,l) (j,k,l)连有向边,就是求每条边经过次数固定的欧拉路径个数。

然后就是BEST定理板子了。

### 如何在 Unity 中将项目导出或构建为 Linux 版本 #### 构建设置调整 为了使 Unity 项目能够针对 Linux 进行编译,在 Unity 编辑器中需进入 `File` -> `Build Settings...` 单选项。在此界面内,选择平台列表中的 `Linux (64-bit)` 或者 `Linux (Universal)` 来指定目标操作系统架构[^1]。 #### 配置其他设置 切换至所选的 Linux 平台之后,点击 `Player Settings…` 可进一步自定义应用属性,比如公司名称、产品名等元数据信息。对于某些高级配置项如最低 API Level 的设定,则通常是在 Android 平台上考虑的因素[^2];而在 Linux 下一般不需要特别关注此参数。 #### 添必要的依赖库和支持文件 当准备就绪后,可能还需要额外引入一些特定于 Linux 发布所需的资源或插件。这一步骤类似于描述过的导入 SDK 和添依赖库的过程,不过具体取决于项目的实际需求。 #### 线程编程注意事项 值得注意的是,在开发过程中如果涉及到线程操作,务必记住只能从主线程访问 Unity 组件和执行系统调用。因此应当合理安排任务调度逻辑以避免潜在的竞争条件问题[^4]。 ```csharp // 示例:确保只在线程安全的方式下更新UI或其他Unity对象 private object _lockObject = new object(); void Update() { lock (_lockObject) { // 安全地修改场景内的物体状态 } } ``` 完成以上准备工作以后,只需按下 `Build And Run` 即可启动构建流程并将应用程序部署到选定的目标环境中去测试其功能是否正常运作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值