可怜的复杂度

news/2025/3/14 21:17:01/文章来源:https://www.cnblogs.com/Lour688/p/18772894

题目链接 link

(转载)(看不懂)
我们用 \(x\) 表示输入的数组,\(y\) 表示变化后的数组,用 \(x[l:r]\) 表示数组 \(x\) 的区间 \([l,r]\) 形成的子数组。

对于两个区间 \([l_1,r_1]\)\([l_2,r_2]\),如果 \(x[l_1:r_1] \neq x[l_2,r_2]\),那么 \(y[l_1:r_1]\) 必定也不等于 \(y[l_2:r_2]\)。所以我们可以把 \(x\) 的每一个本质不同的子区间分开来考虑。

对于一个长度为 \(k\) 的子数组 \(z\),假设它在 \(x\) 出现了 \(t\) 次,这 \(t\) 次出现的左端点下标从左到右依次为 \(a_1, \cdots, a_t\)。我们只需要计算这 \(t\) 次出现在 \(N\) 种可能的数组中一共贡献了多少本质不同的子串,最终的答案就是所有本质不同的子区间的贡献之和。

考虑容斥,对于 \(A = \{a_1, \cdots, a_t \}\) 的每一个非空子集 \(B = \{b_1, \cdots, b_w\}\),我们计算有多少种可能的 \(y\) 让这 \(w\) 次出现都相同(记作 \(c(B)\)),那么子数组 \(z\) 对答案的贡献就是:

\[\sum_{B \subseteq A, |B| > 0} (-1)^{|B| - 1} \times c(B) \]

先考虑如何计算 \(c(B)\)。在 \(B\) 给定的情况下,\(x\) 的每一个位置都有两种可能:被某一次出现(即某个 \([b_i: b_i+k-1]\) )覆盖到了或者没有被任何一次出现覆盖。对于后者,这个位置的值可以任意选取,它对答案的贡献是乘上 \(m\)。所以我们只需要考虑第一种情况就行。

对于第一种情况的所有位置,如果 \(y[b_1:b_1+k-1]\) 的值已经确定了,那么所有第一种情况的位置的值都已经确定了。但是问题在于有些 \(y[b_1:b_1+k-1]\) 的值不合法。比如说 \(n=3,k=2,B=\{1,2\}\),那么 \(y[1:2]\) 中的两个字符必须相等,比如串 \(y[1:2]\) 肯定不等于 \(y[2:3]\)

考虑相邻的两次出现 \(b_i\)\(b_{i+1}\),如果这两次出现相交了,即 \(b_i + k -1 \ge b_{i+1}\),那么就对 \(y[b_1:b_1+k-1]\) 产生了一个约束:这个串的长度为 \(b_i+k-b_{i+1}\) 的后缀和前缀必须相等,即存在长度为 \(b_{i}+k-b_{i+1}\) 的 border。要计算 \(c(B)\),只需要把所有限制都考虑进来,这些限制把 \(y[b_1:b_1+k-1]\) 的位置划分成了若干个等价类,每一个等价类的值都是可以任意取的,因此如果有 \(i\) 个等价类,那么第一类位置的取值方案数就是 \(m^i\)

我们令划分出的等价类为一个串的“状态”,\(f(n)\) 表示长度为 \(n\) 的字符串的不同状态数。举例来说,\(f(3) = 3\),它们分别是三个位置都不要求相同,第一个位置和第三个位置必须相同,三个位置必须都相同。一个有趣的结论是,\(f(n)\) 的大小并不是很大:\(f(50) = 2249, f(100)=35200\)。所以我们可以考虑把当前的等价类划分给压进动态规划的状态里。

我们考虑从左到右依次把 \(A\) 中的元素给加入到 \(B\) 里,令 \(g[i][j][S]\) 表示当前考虑到了 \(a_i\) 并把 \(a_i\) 加入到了 \(B\) 中,当前 \(B\) 的大小是 \(j\),等价类状态是 \(S\) 时的贡献,那么每一次就是枚举下一个加入 \(B\) 中的位置 \(a_t\),然后根据 \(a_t\)\(a_i\) 之间是否重叠、重叠长度来更新 \(S\),把对应的贡献转移到 \(g[t][j+1][S']\)

直接这么写可能会超时,需要用两个 trick 来进行优化:

  1. 我们并不关心 \(B\) 的大小,只关心 \(B\) 大小的奇偶,因此在状态里只需要记录大小的奇偶性就行。
  2. \(k\) 比较大的时候,一些状态是不可达的:最长的重叠长度只有 \(n-k\)。排除掉所有不可达的等价状态可以加速。
#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <string>
using namespace std;const int MOD = 998244353;// 计算所有本质不同子区间的数量
int countDistinctSubarrays(const vector<int>& arr) {unordered_set<int> uniqueSubarrays;int n = arr.size();for (int i = 0; i < n; ++i) {int subarray=0;for (int j = i; j < n; ++j) {subarray = subarray*10+arr[j];uniqueSubarrays.insert(subarray);}}return uniqueSubarrays.size();
}int main() {int t;cin >> t;while (t--) {int n, m;cin >> n >> m;vector<int> x(n);for (int i = 0; i < n; ++i) {cin >> x[i];}unordered_map<string, int> dp;dp[""] = 1; // 初始状态long long totalComplexity = 0;for (int i = 0; i < n; ++i) {unordered_map<string, int> newDp;for (const auto& [key, value] : dp) {for (int j = 1; j <= m; ++j) {string newKey = key + to_string(x[i] * m + j) + ",";newDp[newKey] = (newDp[newKey] + value) % MOD;}}dp.swap(newDp);}for (const auto& [key, value] : dp) {vector<int> arr;size_t start = 0;size_t end = key.find(",");while (end != string::npos) {arr.push_back(stoi(key.substr(start, end - start)));start = end + 1;end = key.find(",", start);}totalComplexity = (totalComplexity + (long long)countDistinctSubarrays(arr) * value) % MOD;}cout << totalComplexity << endl;}return 0;
}

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

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

相关文章

线程异步处理任务

实际开发中,service层可能会执行多个步骤,那有些步骤可能和主任务没有太大关联,那我们可以采用线程去处理,这样就提高响应速度,当然也可以采用MQ,此处介绍的是用线程处理 1、controller层@GetMapping("/thread")public void thread(){demo1Service.process();}…

08. 通用定时器

一、什么是通用定时器ESP32 S3 芯片配备了两个通用定时器组,每组均包含两个通用定时器和一个主系统看门狗定时器。每个通用定时器都具备多个通道。通过明确指定定时器号和通道号,用户可以精准地选定所需的定时器和通道。每个定时器均支持独立编程,并且具备微秒级的精确时间中…

全链路赋能游戏鸿蒙化适配,鸿蒙游戏开发者服务焕新升级

3月14日,华为游戏中心在成都开展了鸿蒙游戏开发者服务日线下活动。本次活动吸引了百余位游戏厂商代表以及开发者参与。华为一线技术专家团队与众多游戏开发者进行了面对面的深入交流,聚焦游戏鸿蒙化全流程技术实践,通过专家授课、案例解析与现场互动,为开发者提供从技术适配…

多线程程序设计(三)——Guarded Suspension

本文摘要了《Java多线程设计模式》一书中提及的 Guarded Suspension 模式的适用场景,并针对书中例子(若干名称有微调)给出一份 C++ 参考实现及其 UML 逻辑图,也列出与之相关的模式。 ◆ 适用场景 当线程访问的共享数据没有准备好时,让该线程进入等待状态,直到数据被准备好…

西部数据企业级硬盘HC310开盘数据恢复,300G左右数据量耗时半年

这块西数4T企业级硬盘HC310是杭州某研究所送过来的,突发损坏不识别,通电后咯吱咯吱敲盘异响,磁头坏了。这款企业级硬盘目前开盘成功率一般,因为磁头适配很困难,需要反复更换磁头,备件成本很高。这种硬盘的开盘难度跟服务器SCSI或SAS硬盘有的一拼,没有经验甚至拆一个废一…

5分钟,构建国产数据库智能体

近期,圈里很多朋友,都尝试利用 DeepSeek 构建自己的智能体。我也利用腾讯元器,将个人公众号内容做了个智能体,可以实现简单的问答。那么延展来看,智能体除了可利用公众号内容,也可使用离线文件等方式来构建。这不禁让我考虑,是否可用这样方式构造一个数据库智能体。说干…

Ubuntu 22.04 LTS 基于 Docker 部署 WordPress

Ubuntu 22.04 LTS 基于 Docker 部署 WordPress 1. 引言 WordPress 是全球最受欢迎的内容管理系统 (CMS),使用 Docker 可以简化其部署过程。本教程将介绍如何在 Ubuntu 22.04 LTS 上使用 Docker 部署 WordPress。2. WordPress 简介 2.1 WordPress 是什么? WordPress 是全球最流…

7.接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例1:输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示…

K近邻算法等

1. KNN算法和KD - tree总结 1.1 KNN算法 模型 K近邻(K - Nearest Neighbors,KNN)算法是一种基本的分类与回归方法。它的模型实际上是对特征空间的划分,给定一个训练数据集,对于新的输入实例,在训练数据集中找到与该实例最邻近的 \(K\) 个实例,然后根据这 \(K\) 个实例的…

正则表达式--java进阶day06

1.正则表达式2.正则表达式的规则、使用3.字符类讲解如图,单独一个a满足正则表达式的规则,所以返回true当删去[]后,正则表达式中的规则就会变为必须是abc,否则不满足条件,即使有一个a该规则是指a-d或者m-p,可以写成[a-dm-p]4.预定义字符类注意事项 正则表达式中存在数量问…

探秘Transformer系列之(13)--- FFN

从零开始解析Transformer,目标是:(1) 解析Transformer如何运作,以及为何如此运作,让新同学可以入门;(2) 力争融入一些比较新的或者有特色的论文或者理念,让老鸟也可以有所收获。探秘Transformer系列之(13)--- FFN 目录探秘Transformer系列之(13)--- FFN0x00 概述0x01…

EXCEL-时间函数

💖简介 在Excel中,时间函数用于处理和操作日期和时间数据; 以下是Excel中常用的时间函数及其常见应用场景的总结.📖函数 ⭐时间函数基础 🌟TIME语法:TIME(hour, minute, second) 功能:将小时、分钟、秒转换为时间序列号(0到0.99999999之间的数值)。 示例:TIME(9,30…