1.23字符串dp+kmp思路

news/2025/1/23 23:21:17/文章来源:https://www.cnblogs.com/fufuaifufu/p/18688766

题目:P1470 [USACO2.3] 最长前缀 Longest Prefix

题目解析

问题描述

给定一个元素集合 ( P ) 和一个大写字母序列 ( s ),要求找到 ( s ) 的最长前缀 ( s' ),使得 ( s' ) 可以由 ( P ) 中的元素组成。元素可以重复使用,但不一定要全部出现。

解题思路

  1. 输入处理
    • 读取元素集合 ( P ),并将其按长度存储在不同的 set 中。
    • 读取大写字母序列 ( s ),并将其拼接成一个连续的字符串。
  2. 动态规划
    • 使用一个动态规划数组 dp,其中 dp[i] 表示前 i 个字符的前缀是否可以由 ( P ) 中的元素组成。
    • 初始化 dp[0] = 1,表示空前缀是合法的。
    • 对于每个位置 i,从 i 向前查找长度不超过 ( m ) 的子串 tt,检查 tt 是否存在于集合 s[tt.size()] 中,并且 dp[i - tt.size()] 是否为 1
    • 如果上述条件满足,则更新 dp[i] = 1,并记录当前前缀的长度 ans
  3. 输出结果
    • 输出 ans,即最长合法前缀的长度。

代码实现

#include <iostream>
#include <set>
#include <cstring>
using namespace std;
int dp[200005], m;
set<string> s[20];
int main() {string tp;while (cin >> tp) {if (tp == ".") break;s[tp.size()].insert(tp); // 存到他大小的集合中m = max(m, int(tp.size()));}int i, ans = 0;dp[0] = 1; // 初始化string n;n = " ";while (cin >> tp) {n = n + tp; // 将所有的串合成一个}for (i = 1; i < n.size(); i++) { // 枚举子串for (int j = min(i, m); j >= 1; j--) {string tt = n.substr(i - j + 1, j); // 截除子串if (s[tt.size()].count(tt) == 1 && dp[i - j] == 1) { // 如果合法ans = i; // 必定是最大的dp[i] = 1; // 本身也合法break; // 没必要搜下去了}}}cout << ans;return 0;
}

代码解释

  1. 输入处理
    • while (cin >> tp) 读取元素集合 ( P ),直到遇到 .
    • s[tp.size()].insert(tp) 将每个元素按长度存储在对应的 set 中。
    • m = max(m, int(tp.size())) 记录集合中元素的最大长度。
  2. 动态规划数组初始化
    • dp[0] = 1,表示空前缀是合法的。
  3. 读取并处理大写字母序列 ( s )
    • n = " " 初始化一个空字符串,用于拼接输入的多行字符串。
    • while (cin >> tp) 读取多行字符串,并将其拼接成一个连续的字符串 n
  4. 动态规划状态转移
    • for (i = 1; i < n.size(); i++) 从第 1 个字符开始,逐个字符处理。
    • for (int j = min(i, m); j >= 1; j--) 从当前位置 i 向前查找长度不超过 m 的子串 tt
    • string tt = n.substr(i - j + 1, j) 截取子串 tt
    • if (s[tt.size()].count(tt) == 1 && dp[i - j] == 1) 检查 tt 是否存在于集合 s[tt.size()] 中,并且 dp[i - j] 是否为 1
    • ans = i 更新最长合法前缀的长度。
    • dp[i] = 1 标记当前前缀为合法。
    • break 退出内层循环,避免不必要的检查。
  5. 输出结果
    • cout << ans 输出最长合法前缀的长度。

示例解析

为了更好地理解这个算法,我们可以通过图解来分析动态规划的过程。假设我们有以下输入:
输入:

A AB BA CA BBC
.
ABABACABAABC

1. 输入处理

首先,我们读取元素集合 P 并将其存储在 set 中,按长度分类:

  • s[1] 存储长度为 1 的元素:{A}
  • s[2] 存储长度为 2 的元素:{AB, BA}
  • s[3] 存储长度为 3 的元素:{CA}
  • s[4] 存储长度为 4 的元素:{BBC}
    最大长度 m 为 4。

2. 初始化动态规划数组

  • dp[0] = 1,表示空前缀是合法的。

3. 读取并处理大写字母序列 s

将输入的多行字符串拼接成一个连续的字符串 n

n = " ABABACABAABC"

4. 动态规划状态转移

我们从第 1 个字符开始,逐个字符处理,尝试找到最长的合法前缀。

位置 1: n[1] = 'A'

  • 检查 n[1:1] 是否在 s[1] 中:A 存在。
  • dp[0] = 1,所以 dp[1] = 1
  • ans = 1

位置 2: n[2] = 'B'

  • 检查 n[2:2] 是否在 s[1] 中:B 不存在。
  • 检查 n[1:2] 是否在 s[2] 中:AB 存在。
  • dp[0] = 1,所以 dp[2] = 1
  • ans = 2

位置 3: n[3] = 'A'

  • 检查 n[3:3] 是否在 s[1] 中:A 存在。
  • dp[2] = 1,所以 dp[3] = 1
  • ans = 3

位置 4: n[4] = 'B'

  • 检查 n[4:4] 是否在 s[1] 中:B 不存在。
  • 检查 n[3:4] 是否在 s[2] 中:BA 存在。
  • dp[2] = 1,所以 dp[4] = 1
  • ans = 4

位置 5: n[5] = 'A'

  • 检查 n[5:5] 是否在 s[1] 中:A 存在。
  • dp[4] = 1,所以 dp[5] = 1
  • ans = 5

位置 6: n[6] = 'C'

  • 检查 n[6:6] 是否在 s[1] 中:C 不存在。
  • 检查 n[5:6] 是否在 s[2] 中:AC 不存在。
  • 检查 n[4:6] 是否在 s[3] 中:CAB 不存在。
  • 检查 n[3:6] 是否在 s[4] 中:BAC 不存在。
  • dp[6] = 0ans 保持为 5。

位置 7: n[7] = 'A'

  • 检查 n[7:7] 是否在 s[1] 中:A 存在。
  • dp[6] = 0,所以 dp[7] = 0
  • 检查 n[6:7] 是否在 s[2] 中:CA 存在。
  • dp[5] = 1,所以 dp[7] = 1
  • ans = 7

位置 8: n[8] = 'B'

  • 检查 n[8:8] 是否在 s[1] 中:B 不存在。
  • 检查 n[7:8] 是否在 s[2] 中:AB 存在。
  • dp[6] = 0,所以 dp[8] = 0
  • 检查 n[6:8] 是否在 s[3] 中:CAB 不存在。
  • 检查 n[5:8] 是否在 s[4] 中:BAC 不存在。
  • dp[8] = 0ans 保持为 7。

位置 9: n[9] = 'A'

  • 检查 n[9:9] 是否在 s[1] 中:A 存在。
  • dp[8] = 0,所以 dp[9] = 0
  • 检查 n[8:9] 是否在 s[2] 中:AB 存在。
  • dp[7] = 1,所以 dp[9] = 1
  • ans = 9

位置 10: n[10] = 'A'

  • 检查 n[10:10] 是否在 s[1] 中:A 存在。
  • dp[9] = 1,所以 dp[10] = 1
  • ans = 10

位置 11: n[11] = 'B'

  • 检查 n[11:11] 是否在 s[1] 中:B 不存在。
  • 检查 n[10:11] 是否在 s[2] 中:AB 存在。
  • dp[9] = 1,所以 dp[11] = 1
  • ans = 11

位置 12: n[12] = 'C'

  • 检查 n[12:12] 是否在 s[1] 中:C 不存在。
  • 检查 n[11:12] 是否在 s[2] 中:BC 不存在。
  • 检查 n[10:12] 是否在 s[3] 中:ABC 不存在。
  • 检查 n[9:12] 是否在 s[4] 中:ABBC 不存在。
  • dp[12] = 0ans 保持为 11。

5. 输出结果

最终,最长的合法前缀长度为 11。

图解

我们可以用一个表格来表示 dp 数组的变化:

i 0 1 2 3 4 5 6 7 8 9 10 11 12
n A B A B A C A B A A B C
dp 1 1 1 1 1 1 0 1 0 1 1 1 0
ans 0 1 2 3 4 5 5 7 7 9 10 11 11

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

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

相关文章

### 深入敏捷之道:PSM认证与高效实践的结合

深入敏捷之道:PSM认证与高效实践的结合​ 在敏捷开发的世界中,Scrum因其灵活性和高效性成为全球最受欢迎的框架之一。而PSM(Professional Scrum Master)认证则是验证敏捷实践者专业能力的重要指标,不仅能提升个人职业竞争力,还能帮助团队更高效地实现目标。 Professional…

9. SpringCloud Alibaba Sentinel 流量控制、熔断降级、系统负载,热点规则的部署设置讲解

9. SpringCloud Alibaba Sentinel 流量控制、熔断降级、系统负载,热点规则的部署设置讲解 @目录9. SpringCloud Alibaba Sentinel 流量控制、熔断降级、系统负载,热点规则的部署设置讲解1. Sentinel 是什么?2. Sentinel 控制台3. Sentinel 下载&安装&运行4. Sentine…

MySQL训练营-慢查询诊断问题

慢查询相关参数和建议配置 slow_query_log + long_query_time 日志开关,是否记慢查询日志以及超过多长时间判定为慢查询。 查看参数设置:SHOW VARIABLES LIKE slow_query_log; SHOW VARIABLES LIKE long_query_time;实践建议:set global long_query_time=1; 分析型业务,set…

并发编程 - 线程同步(一)

线程同步确保多线程环境下共享资源安全使用,避免竞争条件和数据不一致。实现方式有避免资源共享、用户模式同步、内核模式同步和混合模式同步。经过前面对线程的尝试使用,我们对线程的了解又进一步加深了。今天我们继续来深入学习线程的新知识 —— 线程同步。01、什么是线程…

API接口开发设计

写接口看似是一个很简单的事情,但是往往越简单的事情越不容易做好,让我们看看如何写好一个接口。 01. 什么是接口 接口其实是一种规范,在生活中随处可见,比如:不同厂商的水管使用统一的水管接口对接、电脑厂商和配件厂商按照统一的 USB 接口标准进行生产完成配对、应用程序…

FZU ACM寒假集训专题一

只有前四题是自己做的,都ac。 做题思路: 前三题比较简单。第四题想法是,一个一个读字母,按照asc码值分别存储个数,用轮数减个数得出还缺几个,最后加在一起。 中间因为不清楚scanf,让getchar读到换行符出错了。 学习总结: 本专题学习了时空复杂度的计算,c++语法糖,还有…

谷歌泰坦:Transformer之后的AI时代?

介绍 2017年,谷歌发布了一篇具有革命性意义的论文,题为《Attention is All You Need》(注意力是你所需要的一切)。这篇论文引发了我们今天所经历的AI革命,并引入了Transformer模型。Transformer已经成为如今几乎所有顶级大型语言模型(LLM)的核心架构。 Transformer的优势…

2025.1.23冠词

错误分析: 对于冠词知识点掌握不透彻 需掌握知识点: ‌冠词‌是英语语法中的重要概念,主要分为不定冠词(a/an)和定冠词(the),此外还有零冠词。冠词本身不能单独使用,也没有词义,主要用于帮助指明名词的含义。‌ 不定冠词(a/an) ‌用法‌:不定冠词用于单数可数名词…

2025多校冲刺省选模拟赛7

2025多校冲刺省选模拟赛7\(T1\) A. 三色卡(card) \(0pts\)如果存在一个小矩形和大矩形的大小相同,此时另外两个矩形可以任意放,贡献是容易计算的。否则至少需要一个小矩形覆盖大矩形的两个角,通过交换长、宽钦定完全覆盖行的矩形比完全覆盖列的矩形的数量多。完全覆盖行的矩…

重试机制与 CompletableFuture 拓展

重试机制与 CompletableFuture 拓展 禁止转载。 本文旨在讨论重试机制的特点和策略,分析常用重试类库的实现,讨论为 CompletableFuture 添加重试机制的方法。文章首发同名公众号,欢迎关注。 重试示例 以下是一个常见的使用异步重试的例子,当我们需要重试功能时,只需调用 r…

DL00765-光伏故障检测高分辨率无人机热红外图像细粒度含数据集4000+张

光伏发电作为清洁能源的重要组成部分,近年来得到了广泛应用。然而,随着光伏电站规模的扩大,光伏组件在运行过程中可能会出现各种故障,如热斑、遮挡、接线盒故障等。这些故障不仅会影响光伏电站的发电效率,还可能导致更严重的安全隐患。因此,准确、及时地检测并分类这些故…

VMware安装RHEL7.9

VMware安装 可以选择官网下载或者使用其他网盘资源下载。 需要注意的是,现在官网下载需要注册其账号。 下面是安装的详细步骤: 1.找到文件所在路径。双击打开之后,可能会出现环境初始化重启。重启即可。然后再次双击打开此软件。2.勾选《我接受许可协议中的条款》。3.选择安…