[Coci2011]kamion 题解

news/2024/10/24 22:03:57/文章来源:https://www.cnblogs.com/XuYueming/p/18500393

前言

题目链接:Hydro & bzoj;黑暗爆炸。

题意简述

给你一张 \(n\) 个点 \(m\) 条边的有向图。有 \(p\) 种括号,每条边的边权可以是这 \(p\) 种括号中某一种的左括号或者右括号,也可以为空。问你有多少条从 \(1\) 开始到 \(n\) 的长度小于等于 \(k\) 的路径,满足括号匹配,或者剩余若干未配对的左括号。答案对 \(10007\) 取模。

\(2 \leq n \leq 50\)\(1 \leq m \leq n(n-1)\)\(1 \leq k \leq 50\)\(p = 26\)

题目分析

一眼 DP。考虑状态,显然不可以把栈压到状态里,那我们干脆不记栈了,设 \(f_{i, u, v}\) 表示 \(u\)\(v\),经过了恰好 \(i\) 条边,且此时栈为空的方案数。但是答案可以剩余左括号,所以不妨再记 \(h_{i, u, v}\) 表示栈中剩余若干未匹配的左括号,并且这些括号会一直留到最后。

这看起来十分正确,我们可以枚举中转点 \(w\),再枚举 \(u \rightarrow w\)\(w \rightarrow v\) 分别经过了多少条边,两个子问题方案数累乘后做一遍累加即可:\(f_{i, u, v} = \sum \limits _ {w = 1} ^ n \sum \limits _ {t = 1} ^ {i - 1} f_{t, u, w} f_{i - t, w, v}\)。而 \(h\) 只不过是多了一种无用左括号的转移:\(g_{i, u, v} = \sum \limits _ {w \in \operatorname{out}(u)} g_{i - 1, w, v}\)

事实上,这种做法存在「重复统计」的问题。具体来讲,如果一条路径形如 \(u {\tt ()()()} v\),会被 \(u {\color{red} \tt ()} w {\color{purple} \tt ()()} v\)\(u {\color{red} \tt ()()} w {\color{purple} \tt ()} v\) 统计到。怎么解决呢?

事实上,回顾我们序列上的括号匹配问题,即「区间 DP」,同样存在这种重复统计。那我们是怎么去除呢?发现,只要保证转移的时候,是「第一次」进行某一个操作,例如,「第一次」放置一个矩形([CEOI2009] photo),就能够保证每一种情况只会被统计到一次(因为「第一次」是唯一的)。括号匹配的「第一次」便是「第一次」成为一个匹配的括号串。

区间上如此,图上亦如此。我们考虑枚举的中转点是「第一次」成为一个匹配的括号串的位置,也即,保证 \(u \rightarrow w\) 的路径两端是一对匹配上的括号(\(u\ \texttt{(...)}\ v\))。我们可以记一个 \(g_{i, u, v}\),和 \(f\) 定义类似,只不过保证 \(u \rightarrow v\) 的路径两端是一对匹配上的括号。这样,我们的 \(f\) 就能够通过 \(g\)\(f\) 的路径拼接而来:\(f_{i, u, v} = \sum \limits _ {w = 1} ^ n \sum \limits _ {t = 1} ^ {\color{red} \mathbf{i}} g_{t, u, w} f_{i - t, w, v}\)。注意,此时 \(t\) 的上界是 \(i\),因为对于 \(u\ \texttt{(...)}\ v\) 本身就合法。当然,\(h\) 同样如此。

我们把目光聚焦在求出 \(g\) 身上。我们不难发现,如果把最外层的那对括号扒掉,不就剩下一个形如 \(f\) 的括号串了吗?所以,我们只需要在 \(f_{i - 2}\) 的基础上,外层包裹一对括号即可:\(g_{i, u, v} = \sum \limits _ {tp = 1} ^ {p} \sum \limits _ {(u', tp) \in \operatorname{out}(u)} \sum \limits _ {(v', tp) \in \operatorname{in}(v)} f_{i - 2, u', v'}\)

答案没什么好说的,就是 \(\sum \limits _ {i = 0} ^ k h_{i, 1, n}\)

时间复杂度 \(\Theta(kn^4 + k^2n^3) = \Theta(kn^3(n + k))\),空间复杂度 \(\Theta(kn^2)\)

代码

#include <cstdio>const int N = 51;using mint = unsigned short;
const mint mod = 10007;
inline mint add(mint a, mint b) { return a >= mod - b ? a + b - mod : a + b; }
inline mint mul(mint a, mint b) { return int(a) * b % mod; }
inline void toadd(mint &a, mint b) { a = add(a, b); }int n, m, k;
char out[N][N], in[N][N], op;
bool emp[N][N];mint f[N][N][N], h[N][N][N], g[N][N][N];signed main() {scanf("%d%d%d", &n, &m, &k);for (int u, v; m--; ) {scanf("%d%d", &u, &v);while ((op = getchar()) == ' ');if ('A' <= op && op <= 'Z') out[u][v] = op - 'A' + 'a';else if ('a' <= op && op <= 'z') in[u][v] = op;else emp[u][v] = true;}for (int i = 1; i <= n; ++i) f[0][i][i] = h[0][i][i] = 1;for (int i = 1; i <= k; ++i) {if (i >= 2) {for (int u = 1; u <= n; ++u)for (int $u = 1; $u <= n; ++$u) if (out[u][$u])for (int v = 1; v <= n; ++v)for (int $v = 1; $v <= n; ++$v) if (out[u][$u] == in[$v][v])toadd(g[i][u][v], f[i - 2][$u][$v]);}for (int w = 1; w <= n; ++w)for (int u = 1; u <= n; ++u)for (int v = 1; v <= n; ++v) {if (emp[u][w]) toadd(f[i][u][v], f[i - 1][w][v]);if (emp[u][w] || out[u][w]) toadd(h[i][u][v], h[i - 1][w][v]);for (int l = 1; l <= i; ++l) {toadd(f[i][u][v], mul(g[l][u][w], f[i - l][w][v]));toadd(h[i][u][v], mul(g[l][u][w], h[i - l][w][v]));}}}mint ans = 0;for (int i = 0; i <= k; ++i) toadd(ans, h[i][1][n]);printf("%hu", ans);return 0;
}

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

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

相关文章

免费的erp系统有哪些

在市场上,有一些免费的ERP系统,它们提供了成本效益高、功能齐全的解决方案。这些系统包括:1. Odoo;2.Dolibarr;3.ERPNext;4.xTuple PostBooks;5.FrontAccounting;6.Apache OFBiz;7.Metasfresh。Odoo是一个全面的开源ERP解决方案,适用于中小型企业,尤其是那些需要高度…

扩展KMP

前言 扩展KMP又称Z函数,可以快速的求出一个字符串的每一个后缀的与其的LCP(最大公共前缀)长度。 至于为什么要学习exKMP,因为(数据规模很上进)我们都是上进的OIer。 算法思路 暴力朴素的算法 将\(n\)个字符的字符串S中第\(i\)位开始的后缀与S的开头一一比较,求出LCP数组…

运算

模二加(异或)运算模 即取余 模运算 当两个整数 a 和 b 模 n 同余,记作 a≡b(mod n),意味着 a 和 b 被 n 除后余数相同。 基本性质:封闭性:如果 a≡b(mod n) 且 c≡d(mod n),那么 a+c≡b+d(mod n),以及 a⋅c≡b⋅d(mod n)。 乘法逆元:对于任何整数 a 和正整数 n,存在一…

Knapsack题解

题面下划线:符合单调性 举例:k=3W : 1 2 3 4 5V : 6 5 1 2 4g: 15 11 7 6 4

Win11安装基于WSL2的Ubuntu

详细介绍了Win11安装基于WSL2的Ubuntu的过程。1. 概述 趁着还没有完全忘记,详细记录一下在Win11下安装基于WSL2的Ubuntu的详细过程。不得不说WLS2现在被微软开发的比较强大了,还是很值得安装和使用的,笔者就通过WLS2安装的Ubuntu成功搭建了ROS环境。 2. 详论 2.1 子系统安装…

什么是芯片领域的敏捷设计(Agile Development)

芯片领域的敏捷设计是一种灵活的开发方法,致力于更快速、更高效地开发和优化集成电路(IC)和半导体技术。其核心特点包括:1、迭代开发;2、跨功能团队合作;3、客户反馈导向;4、及时响应变更。其中,迭代开发强调分阶段、小步快跑的设计方法,有助于快速地调整和优化设计。…

Clickhouse基本使用方法详细讲解(包括详细步骤及相关操作截图)

超详细ClickHouse学习笔记 一、ClickHouse概述 ClickHouse是一个用于在线分析处理查询(OLAP)的列式数据库管理系统(DBMS)。它由Altinity公司开发,支持线性扩展和高性能的数据压缩。ClickHouse以其卓越的数据处理速度而闻名,特别适合于大规模数据集的实时查询和分析。OLTP…

高ROI的行业或项目一般有什么样的特点

高ROI的行业或项目一般的特点有:1、市场需求的洞察;2、有效的成本控制;3、创新和技术应用;4、强大的市场定位;5、风险管理。实现高ROI的项目通常基于对市场需求的深刻洞察。这意味着项目管理者或企业家需要了解消费者的需求,预测市场趋势,并能够提供满足这些需求的产品或…

IDEA如何更改背景桌面图片

前言 我们在使用IDEA开发Java应用时,经常对着屏幕,有时候也感觉有点枯燥,这时候,就可以设置一个背景图片来缓解一下,比如说设置一张风景图片,或者设置一个美女图片,哈哈哈。 那么,我们可以如何设置呢? 如何设置 首先,我们打开设置面板。然后,我们点击下【Appearance…

灰色代码部分:要是输入名字列表,又能输出结果,但是空列表的时候就输出不了?

大家好,我是Python进阶者。 一、前言 前几天在Python白银交流群【Aciel】问了一个Python基础的问题,问题如下:灰色代码部分:要是输入名字列表,又能输出结果,但是空列表的时候就输出不了?二、实现过程 这里【瑜亮老师】给了一个指导,具体如下所示:@Aciel 循环 for nam…

assembly2

汇编2 寄存器(不同架构不同) 8086中寄存器均为16位,可存放两个字节(1byte=8bit)。 通用寄存器AX,BX,CX,DX用来存储一般性的数据,被称为通用寄存器。二进制数据在寄存器中是低位存在低地址,高位存在高地址。也可将一个寄存器分为H,L(高8位低8位)来做8位存储器。字在寄存器…

shctf[Week3] 小小cms

看到首页面 了解到YzmCMS的版本,上网搜搜这个版本存在的漏洞 发现存在任意函数调用RCE的漏洞 https://blog.csdn.net/shelter1234567/article/details/138524342 根据文章直接抄payload,进入/pay/index/pay_callback目录下下面cat /flag即可,最终的payload为 out_trade_no[0…