1 条题解
-
0
CF1989B Substring and Subsequence 题解
题意简述
给定两个字符串 和 (长度均 ),求最短的字符串 ,使得:
- 是 的子串(连续出现);
- 是 的子序列(不要求连续,但顺序不变)。
输出 的最小长度。
思路分析
设 ,。
最终构造的 必然包含 作为连续段。同时, 的字符按顺序出现在 中。我们可以将 的字符分为三部分:
- 在 段之前出现的部分( 的某个前缀);
- 在 段内部作为子序列匹配的部分( 的一段连续子串);
- 在 段之后出现的部分( 的某个后缀)。
要使 最短,我们应尽可能多地利用 内部的字符去覆盖 的字符,从而减少需要额外放在 前后的字符数量。
具体地,假设我们能从 中找到 的一个连续子段 作为子序列(即存在 的一些位置,顺序等于 ),那么可以这样构造 :
这样 的长度为:
令 表示 的这段连续子串的长度,那么 。
因此,问题转化为:最大化 ,即 中能作为 的子序列的最长连续子串的长度。
算法实现
我们可以枚举 的每一个起始位置 (),然后用贪心的方式匹配 :从 的第一个字符开始扫描,每当遇到与 当前所需字符相同时,就将 的指针右移。这样能匹配到的最大长度就是从 开始能匹配的最长连续段。
具体过程:
- 外层循环枚举 作为 的起始位置。
- 内层两个指针 (遍历 )和 (初始 ,表示 中当前待匹配位置):
- 若 ,则 右移(匹配成功);
- 始终右移(扫描 )。
- 当 超过 或 超过 时停止,记录 。
对所有 取最大的 ,答案即为 。
时间复杂度:对于每组测试数据,外层 ,内层 ,总计 。,,总计算量约 ,可以轻松通过。
参考代码
#include <iostream> #include <string> #include <algorithm> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int T; cin >> T; while (T--) { string a, b; cin >> a >> b; int n = a.size(), m = b.size(); // 在前面插入一个占位符,使得下标从 1 开始 a = ' ' + a; b = ' ' + b; int max_len = 0; for (int i = 1; i <= m; ++i) { int l = 1, r = i; // l 扫描 a,r 扫描 b while (l <= n && r <= m) { if (a[l] == b[r]) ++r; // 匹配成功,b 指针右移 ++l; // a 指针始终右移 } max_len = max(max_len, r - i); } cout << n + m - max_len << '\n'; } return 0; }
- 1
信息
- ID
- 6888
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者