Codeforces633C Spy Syndrome 2 (单词Trie)
题目链接: Spy Syndrome 2
大致题意
给定一个长度为n的字符串str, 全部由小写字母组成.
接下来给出单词列表, 共包含m个单词, 每个单词由大写和小写字母组成.
字符串str可以保证是由若干个单词组成, 但是进行了加密.
加密操作: 每个单词的所有字母都被转换成小写字母, 并且进行了翻转.
要求你复原出str, 并且在单词与单词之间加上空格输出.
解题思路
本题不推荐看其他用Trie + dfs的题解, 理论上复杂度应该是爆炸了.
网上深搜的做法都是把单词翻转存入Trie, 但是我反过来把str翻转就T59了.
既然翻转str能T59, 那么把Test59的所有数据翻转输入, 理论上也可以T掉网上的dfs代码.
字典树
考虑字符串str中的每个单词都被翻转过, 因此我们不妨考虑把str进行翻转. 这样我们只需要检查str能否由若干个单词拼出即可.
这里相当于查找某个字符串是否已经出现过, 我们可以想到用Trie树来维护.
考虑到单词有大小写, 而str只有小写. 因此我们不妨对单词进行小写转换, 存入Trie中. 对于每个单词结束的位置, 进行标记.
接下来就是我们怎么去拆分str.
我的做法是: 维护一个dp数组, dp[i]存储字符串的前i个字符是否可以被拆成若干个单词表示, 若可以, 则记录当前位置为结束位置的单词编号(记录路径).
例如: 有长度为10的str = “abcdefghij” 单词有: ab fghij fau cde, 依次编号1~4.
那么 dp[2] = 1, dp[5] = 4, dp[10] = 2. 其余dp[i] = 0.
维护dp的方法: 首先我们对于str进行一次匹配, 把所有有单词结尾的位置进行标记(如上例, 我们会标记出dp[2] = 1). 然后进行每个字符位置遍历: 如果当前位置index可以成功匹配, 则对于index+1的位置再次进行匹配.
这样, 最坏的情况下是每一个位置都被标记, 并且每一个位置都能匹配到Trie树末端. 由于str最长的长度为1E4, 而单词的最大长度为1E3, 因此最坏的复杂度为1E7.
最后考虑如何输出这些单词, 由于我们dp数组内部记录了以第i个位置作为结束的字符串编号, 因此我们可以倒推出所有单词.
代码细节: string的下标从0开始, 而我的dp编号从1开始, 请大家注意区分.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E5 + 10, M = 1E6 + 10;
int t[M][26], ind;
int pos[M]; // 对应的字符串编号。int n; string str;
string text[N]; //所有单词
void insert(const string& s, int id) {int x = 0;for (auto& op : s) {char c = tolower(op) - 'a';if (!t[x][c]) t[x][c] = ++ind;x = t[x][c];}pos[x] = id;
}int dp[N];
void ask(int index) {int x = 0;for (int i = index; i < n; ++i) {char c = str[i] - 'a';if (!t[x][c]) return;x = t[x][c];if (pos[x]) dp[i + 1] = pos[x];}
}vector<int> v;
void dfs(int now = n) {if (!now) return;v.push_back(dp[now]);dfs(now - text[dp[now]].size());
}
int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n >> str;reverse(str.begin(), str.end());int m; cin >> m;rep(i, m) {cin >> text[i];insert(text[i], i);}ask(0);rep(i, n) {if (!dp[i]) continue;ask(i); }dfs();for (auto& op : v) cout << text[op] << ' ';puts("");return 0;
}
END
Codeforces633C Spy Syndrome 2 (单词Trie)相关推荐
- CF633C Spy Syndrome 2(字典树+dp)
CF633C Spy Syndrome 2 原题链接 说是 dpdpdp 但是感觉说是一个记忆化也可以.我们定义一个 dpdpdp 数组,其 dp[i]dp[i]dp[i] 含义为将加密串前 iii ...
- CF633C Spy Syndrome 2 trie树
这个模型以前绝对见过,模拟赛的时候开始敲了一个AC自动机,纯属脑抽~ code: #include <bits/stdc++.h> #define N 5000006 #define NN ...
- 洛谷P2412 查单词 [trie树 RMQ]
题目背景 滚粗了的HansBug在收拾旧英语书,然而他发现了什么奇妙的东西. 题目描述 udp2.T3如果遇到相同的字符串,输出后面的 蒟蒻HansBug在一本英语书里面找到了一个单词表,包含N个单词 ...
- CF633C Spy Syndrome 2
嘟嘟嘟 题面:把一句话加密:1.所有字母变成小写.2.翻转所有单词.3.去掉空格.然后给你一句加密后的字符串以及一些出现在原句和没有出现在原句的单词,让你还原原句.注意,每一个单词可以使用多次,如果有 ...
- BZOJ 4567 [SCOI2016]背单词 (Trie树、贪心)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4567 题解: 显然答案一定小于\(n\times n\), 字符串倒过来变成前缀建Tr ...
- Codeforces C. Spy Syndrome 2
题意: 给你一个长度为n的字符串S,和m个字符串T,询问能不能用这些字符串T将他们倒序,然后组成S 题解: 将这些m个字符串T,倒序放入Trie树中,然后用S在Trie树上匹配就好了 AC代码: #i ...
- CF633C Spy Syndrome 2 ACA+DP
思路 首先把原串取反一下,就可以用mmm个正序模式串做匹配了. 定义dp[i]dp[i]dp[i]表示1-i1\dots i1-i的匹配状态(0或1), 然后对mmm个串插入到AC自动机上构造fail ...
- LeetCode 720. 词典中最长的单词(Trie树)
1. 题目 给出一个字符串数组words组成的一本英语词典.从中找出最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成.若其中有多个可行的答案,则返回答案中字典序最小的单词. 若无 ...
- Trie树的常见应用大总结(面试+附代码实现)
(一)Trie的简介 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树.他的核心思想是空间换时间,空间消耗大但 ...
最新文章
- Apache 编译安装
- 最大全0/1子矩阵的探究
- df python 增加数据_【Note】关于玩转数据处理R语言120题的注解(P1-P50)
- mysql优化有哪些着手点_mysql的优化总结
- Matplotlib 三维图像 API
- 黑马程序员——OC学习笔记—— Copy
- 线性二次型调节器(LQR)原理详解
- STM32配置全速USB与Python上位机传输数据步骤
- 【python】使用jieba分词并导出txt
- R语言ROC分析、ROC曲线可视化及最佳阈值计算(threshold、cutoff)
- Dev-C++5.11游戏创作之简易小炸弹
- 全球与中国终末期肾病(ESRD)设备市场现状及未来发展趋势(2022)
- 用Excel绘制统计图的方法
- Linux之nc命令详解
- javascript代码大全
- 2018-09-06 Java实现英汉词典API初版发布在Maven
- Windows 更改终端服务(RDP 远程桌面) 默认远程端口的方法
- matlab pid buck,BUCK电路闭环PID控制系统的MATLAB仿真.doc
- 公式总结-半导体器件物理-3-能带
- linux脚本 ssh 连接,SSH连接管理 (我的第一个shell脚本)