题解:Luogu P11714 [清华集训 2014] 主旋律

news/2025/3/19 12:46:20/文章来源:https://www.cnblogs.com/P2441M/p/18780801

题意简述

给定一个 \(n\) 个点 \(m\) 条边的有向简单图,问有多少种删边的方案,使得删去后整个图是强连通的,答案对 \(10^9+7\) 取模。

对于所有数据,\(1\leq n\leq 15\)\(0\leq m\leq n(n-1)\)

题解

\(\text{Upd 2025/3/14}\):修改了一些笔误。

还是太神仙了。

强连通分量本身是比较难刻画的,但我们可以通过缩点刻画其结构性:若一张图是强连通的,那么它缩点后必然是一个单点,否则就是一个 DAG。DAG 计数是比较经典的,因此考虑正难则反,用 \(2^m\) 减去缩点后图是一个 DAG 的方案数。

先考虑一个比较简单的问题:求这个图中有多少个子图是一个 DAG。对于 DAG 计数,考虑拓扑排序,那么每次拓扑排序的 \(0\) 入度点对图进行了分层,形成了阶段性,很有利于我们进行 DP。令 \(f_S\) 表示 \(S\) 集合的导出子图中 DAG 子图的个数。枚举 \(0\) 入度点集合 \(T\)

\[f_S=\sum_{\substack {T\subseteq S\\T\neq\varnothing}}2^{cnt(T,S\backslash T)}f_{S\backslash T} \]

其中 \(cnt(A,B)=\left|\{(u,v)|(u,v)\in E,u\in A,v\in B\}\right|\),即点集 \(A\) 中的点连向点集 \(B\) 中的点的边数。

但是,上面的转移方程是错误的,因为 \(T\rightarrow S\backslash T\) 的边是乱连的,我们无法保证 \(S\) 恰好\(0\) 入度点集,会算重。而 \(2^{cnt(T,S\backslash T)}f_{S\backslash T}\) 计算的实际上是钦定 \(T\)\(0\) 入度点集的方案数,因此考虑容斥。令 \(f_{T,S}\) 表示 \(S\) 点集中 \(T\) 恰好\(0\) 入度点集的方案数,\(g_{T,S}\) 表示 \(S\)钦定 \(T\)\(0\) 入度点集的方案数。那么可以得到

\[g_{T,S}=2^{cnt(T,S\backslash T)}f_{S\backslash T}=\sum_{T\subseteq R\subseteq S}f_{R,S} \]

根据子集反演,

\[f_{T,S}=\sum_{T\subseteq R\subseteq S}(-1)^{|R|-|T|}g_{T,S} \]

代回再变换求和顺序,可以得到

\[\begin{align*} f_S & =\sum_{\substack {T\subseteq S\\T\neq\varnothing}}f_{T,S} \\ & =\sum_{\substack {T\subseteq S\\T\neq\varnothing}}\sum_{T\subseteq R\subseteq S}(-1)^{|R|-|T|}2^{cnt(R,S\backslash R)}f_{S\backslash R} \\ & =\sum_{R\subseteq S}(-1)^{|R|}2^{cnt(R,S\backslash R)}f_{S\backslash R}\sum_{\substack {T\subseteq R\\T\neq\varnothing}}(-1)^{|T|} \\ & =\sum_{R\subseteq S}(-1)^{|R|+1}2^{cnt(R,S\backslash R)}f_{S\backslash R} \end{align*} \]

这样就解决了 DAG 子图计数问题,同时我们也得到了一个显然的暴力:搜出缩点的方案,然后跑 DAG 子图计数。

考虑怎么优化。我们的暴力是形如搜出缩点方案 \(V=\bigcup_{i=1}^kS_i\),然后答案就是

\[ans_S=2^{cnt(S,S)}-\sum_{S_1,\cdots,S_k}\left(\prod_{i=1}^kans_{S_i}\right)\sum_{\substack{T\subseteq \{S_1,\cdots,S_k\}\\T\neq\varnothing}}(-1)^{|T|+1}2^{cnt(T,S\backslash T)}f_{S\backslash T} \]

变换求和顺序,我们先去枚举 \(T\),即缩点后的零入度点的并集在原图上对应的点集,注意到容斥系数只和零入度点划分成的 SCC 数量有关,并且对于 \(S\backslash T\) 中的点,任意的子图都是合法的。令 \(h_{k,T}\) 表示将 \(T\) 中的点划分成 \(k\) 个互不相连的 SCC 的方案数,那么容易得到

\[ans_S=2^{cnt(S,S)}-\sum_{\substack {T\subseteq S\\T\neq\varnothing}}\sum_{k=1}^{|T|}(-1)^{k+1}h_{k,T}2^{cnt(T,S\backslash T)}2^{cnt(S\backslash T,S\backslash T)} \]

进一步地,容斥系数只跟零入度点划分成的 SCC 数量奇偶性有关,奇数个贡献为正,偶数个贡献为负,容易想到令 \(h_T\) 表示把 \(T\) 划分成奇数个 SCC 的方案数减去划分成偶数个 SCC 的方案数,转移方程变为

\[ans_S=2^{cnt(S,S)}-\sum_{\substack {T\subseteq S\\T\neq\varnothing}}h_T2^{cnt(T,S\backslash T)}2^{cnt(S\backslash T,S\backslash T)} \]

再来考虑 \(h_S\) 的转移。容易想到枚举某个子集 \(T\subseteq S\) 作为其中一个 SCC,但显然会重复,于是我们对其添加限制,改为枚举 \(\operatorname{lowbit}(S)\) 对应点 \(p\) 所在的 SCC,容易得到转移方程:

\[h_S=ans_S-\sum_{\substack{T\subset S\\p\in T}}ans_Th_{S\backslash T} \]

加上 \(ans_S\) 表示将 \(S\) 划分为一整个 SCC,\(\sum\) 前面的负号是因为多出了 \(T\) 这个 SCC,奇偶性改变。

但是这样似乎 \(h\)\(ans\) 似乎会相互转移啊?我们仔细思考,\(ans\) 转移时只会在 \(T=S\) 的时候用到 \(h_S\),而这个的实际意义是 \(S\) 就是一个强连通分量,但 \(\sum\) 处要计算的是不合法的方案数,所以不应该被包含进来,这样就恰好不会相互转移了。也就是说,我们先计算 \(h_S-ans_S\) 的部分,然后计算\(ans_S\),最后给 \(h_S\) 加回 \(ans_S\) 就行了。可以结合代码理解。

时间复杂度是 \(O(3^nn^2)\) 的,无法通过。瓶颈在于计算 \(cnt(T,S\backslash T)\)。暴力计算无法承受,那么考虑固定 \(S\),假设我们得到了较大的 \(T\) 对应的 \(cnt(T,S\backslash T)\),然后尝试递推出当前的 \(cnt(T,S\backslash T)\),这就很简单了,考虑 \(\operatorname{lowbit}(S\backslash T)\) 对应的点 \(p\),那么

\[cnt(T,S\backslash T)=cnt(T\cup\{p\},S\backslash T\backslash \{p\})-cnt(p,S\backslash T\backslash \{p\})+cnt(T,p) \]

而形如 \(cnt(p,T)\) 或者 \(cnt(T,p)\) 的单点到集合的边数显然可以 \(O(2^nn^2)\) 预处理出来,于是我们就可以在枚举 \(S\) 的过程中顺便把所有的 \(cnt(T,S\backslash T)\) 递推出来。总体时间复杂度为 \(O(3^n)\)

代码

int n, m, mat[N][N];
int pw2[M], pc[S], ocnt[N][S], icnt[N][S], cnt[S], f[S], g[S];
int tcnt[S];int main() {ios::sync_with_stdio(false), cin.tie(nullptr);cin >> n >> m;for (int i = 1, u, v; i <= m; ++i) cin >> u >> v, mat[--u][--v] = 1;pw2[0] = 1;for (int i = 1; i <= m; ++i) pw2[i] = (pw2[i - 1] << 1) % MOD;for (int i = 0; i < n; ++i) for (int s = 0; s < 1 << n; ++s)for (int j = 0; j < n; ++j)if (s >> j & 1) ocnt[i][s] += mat[i][j], icnt[i][s] += mat[j][i];for (int s = 1; s < 1 << n; ++s) {int lb = lowbit(s), i = log2(lb), ss = s ^ lb;cnt[s] = cnt[ss] + icnt[i][ss] + ocnt[i][ss];pc[s] = pc[s - lowbit(s)] + 1;}for (int s = 1; s < 1 << n; ++s) {int lb = lowbit(s);for (int t = (s - 1) & s; t; t = (t - 1) & s)if (t & lb) g[s] = (g[s] - 1ll * f[t] * g[s ^ t] % MOD) % MOD;tcnt[s] = 0, f[s] = pw2[cnt[s]];for (int t = s; t; t = (t - 1) & s) {int lb = lowbit(s ^ t), i = log2(lb);if (t != s) tcnt[t] = tcnt[t | lb] - ocnt[i][s ^ t ^ lb] + icnt[i][t];else tcnt[t] = 0;f[s] = (f[s] - 1ll * g[t] * pw2[tcnt[t]] % MOD * pw2[cnt[s ^ t]] % MOD) % MOD;}g[s] = (g[s] + f[s]) % MOD;}cout << (f[(1 << n) - 1] + MOD) % MOD;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/901471.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

库存持有成本的底层运算逻辑是什么?

你可能会觉得,库存持有成本这个概念听起来有点抽象: 库存不就是放在仓库里待着吗,怎么还会“花钱”? 其实,库存持有成本就是你把货物放在仓库里,背后所产生的一系列费用。 这些费用包括仓库租金、保险费用、商品的折旧损耗,还有库存过期的风险等等。 今天,我们就来拆解…

Windows部署deepseek R1训练数据后通过AnythingLLM当服务器创建问答页面

如果要了解Windows部署Ollama 、deepseek R1请看我上一篇内容。 这是接上一篇的。 AnythingLLM是一个开源的全栈AI客户端,支持本地部署和API集成。它可以将任何文档或内容转化为上下文,供各种语言模型(LLM)在对话中使用。以下是关于Windows环境下使用AnythingLLM API的一些…

变量数据类型流程控制

常量变量 常量 1.概述:在代码的运行过程中,值不会发生改变的数据 2.分类:整数常量:所有整数小数常量:所有带小数点的2.5 1.5 2.0字符常量:带单引号的 单引号中必须有且只能有一个内容1(算) 11(不算) (不算) a1(不算) (算) (两个空格不算)写一个tab键(算) 字符…

Vue2-自定义创建项目、ESLint、Vuex及综合案例购物车

Vue2自定义创建项目 基于VueCli自定义创建项目架子 步骤:安装VueCLI脚手架npm i @vue/cli -g 可以通过vue --version 判断是否下载VueCLI在某个文件夹中创建vue项目vue create 项目名称 (项目名中不能包含大写字母)选择Manually select features选择Babel(语法降级)、Ro…

yum install -y devtoolset-8-gcc*

如果执行结果为上面这个结果的话,需要执行以下操作 yum install centos-release-scl*修改CentOS-SCLo-scl.repo文件 baseurl=https://mirrors.aliyun.com/centos/7/sclo/x86_64/rh/ 和 gpgcheck=0修改CentOS-SCLo-scl-rh.repo文件和上面一样查看 [root@iZbp153shsqfoddljmkit4…

几个技巧,教你去除文章的 AI 味!

给大家分享一些快速去除文章 AI 味的小技巧,有些是网上被分享过的,也有些是我个人的经验。学会之后,无论是写工作文案、毕业设计、自媒体文章,还是平时生活中写写好评,都是非常轻松的。最近有不少朋友在利用 AI 写毕业设计论文,几秒钟一篇文章就刷出来的,爽的飞起。 结果…

Sci Chart中的XyDataSeries与UniformXyDataSeries

在 SciChart 中,XyDataSeries 和 UniformXyDataSeries 是两种用于处理数据序列的核心类,主要差异体现在数据存储方式、性能优化及适用场景上。 以下是具体对比: 1. 数据存储与结构差异 **XyDataSeries<TX, TY>** 需要同时存储 X 和 Y 值的完整坐标对。例如,对于每个数…

强化学习基础_基于价值的强化学习

Action-Value Functions 动作价值函数 折扣回报(Discounted Return) 折扣回报 Ut 是从时间步 t 开始的累积奖励,公式为: Rt 是在时间步 t 获得的奖励。γ 是折扣因子(0<γ<1),用于减少未来奖励的权重。这是因为未来的奖励通常不如当前奖励重要,例如在金融领域,未…

USB杂谈

一、USB控制器 OHCI 1.0、1.1控制器 UHCI:1.0、1.1控制器 EHCI 2.0控制器 XHCI 3.0控制器 EHCI 2.0控制器 HID:人机交互接口,鼠标、手柄 、键盘、扫描枪USB协议中对集线器的层数是有限制的,USB1.1规定最多为5层,USB2.0规定最多为7层。 理论上,一个USB主控制器最多可接127个…

2025年3月中国数据库排行榜:PolarDB夺魁傲群雄,GoldenDB晋位入三强

2025年3月排行榜解读出炉,榜单前四现波动,PolarDB时隔半年重返榜首、GoldenDB进入前三,此外更有一些新星产品表现亮眼!欢迎阅读、一起盘点~阳春三月,万物复苏。2025年3月中国数据库流行度排行榜的发布,不仅展现了中国数据库企业在技术创新、生态建设和应用深化方面的显著…

# 20241902 2024-2025-2 《网络攻防实践》第四周作业

1.实验内容 通过本次实验,在搭建的实验环境中完成TCP/IP协议栈重点协议的攻击实验,包括ARP缓存欺骗攻击、ICMP重定向攻击、SYN Flood攻击、TCP RST攻击、TCP会话劫持攻击,并熟悉wireshark、netwox和ettercap等软件的操作。 2.实验过程 实验1 ARP缓存欺骗攻击 本实验中Kali为…