洛谷P3808 【模板】AC自动机(简单版) AC自动机

网址:https://www.luogu.org/problem/P3808

题意:

给定$n$个模式串和$1$个文本串,求有多少个模式串在文本串里出现过,相同的模式串需要多次计算。

题解:

$AC$自动机的模板题。$AC$自动机是基于$Trie$树的有限状态自动机,又称$Trie$图,$AC$自动机的结点的$fail$指针构造方法如下:在$Trie$树上,类似于$KMP$的$fail$指针,对于非空结点,找到其父亲的$fail$指针对应的结点的相同字母的儿子结点。对于空节点,直接把它连到其父亲的$fail$指针对应的结点的相同字母的儿子结点,根结点的儿子的$fail$指针指向根,形成转移图。然后查询的时候,我们要求的是求出现次数,所以我们当到达一个结点的时候,我们可以跳$fail$指针匹配其后缀,然后匹配过的加上标记防止重新匹配。

#include <iostream>
#include <string>
#include <queue>
using namespace std;
#define maxn int(2e6+5)
int trie[maxn][26];
int cntword[maxn];
int fail[maxn];
int cnt = 0;
struct ac
{
	void insert(string& str)//插入字符串
	{
		int root = 0, next;
		for (int i = 0; i < str.size(); ++i)
		{
			next = str[i] - 'a';
			if (!trie[root][next])
				trie[root][next] = ++cnt;//将字符的位置按照放入顺序递增
			root = trie[root][next];
		}
		++cntword[root];//该位置单词结束
	}
	void buildfail()
	{
		queue<int>que;
		for (int i = 0; i < 26; ++i)
		{
			if (trie[0][i])
			{
				fail[trie[0][i]] = 0;//根的儿子的fail一定指向根
				que.push(trie[0][i]);//将其放入队列
			}
		}
		while (!que.empty())
		{
			int now = que.front();//出队,以其为根
			que.pop();
			for (int i = 0; i < 26; ++i)
			{
				if (trie[now][i])
				{
					fail[trie[now][i]] = trie[fail[now]][i];//fail指向其父节点的fail对应的相同子节点
					que.push(trie[now][i]);
				}
				else
					trie[now][i] = trie[fail[now]][i];//空节点是其父节点对应fail的相同儿子
			}
		}
	}
	int query(string& str)
	{
		int now = 0, ans = 0;
		for (int i = 0; i < str.size(); ++i)
		{
			now = trie[now][str[i] - 'a'];
			for (int j = now; j && cntword[j] != -1; j = fail[j])//匹配根到当前结点的子串的后缀以节省时间
			{
				ans += cntword[j];
				cntword[j] = -1;
			}
		}
		return ans;
	}
};
int main()
{
	string tmp;
	ios::sync_with_stdio(0);
	cin.tie(0);
	ac AC;
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		cin >> tmp;
		AC.insert(tmp);
	}
	fail[0] = 0;
	cin >> tmp;
	AC.buildfail();
	cout << AC.query(tmp) << endl;
	return 0;
}

  

AC代码:

 

转载于:https://www.cnblogs.com/Aya-Uchida/p/11559806.html

<think>好的,用户现在问的是关于3.4有没有学习路线,我需要先回顾之前的对话。之前用户问的是学习C++刷题和算法需要补充的知识点及优先级,我给出了详细的分类和排序。现在用户提到的“3.4”可能是指之前回复中的某个编号,比如第三部分第四点,或者可能是个排错误。 首先,检查之前的回复结构。之前的回答分为四个部分:一、C++核心知识点;二、算法工程能力;三、优先级总排序;四、实践建议。在第三部分总排序中,列出了1到5点,但并没有3.4这样的编号。所以可能用户是误输入,或者“3.4”指其他内容,比如可能用户想询问学习路线的第三点第四部分,或者可能是个笔误。 考虑到用户之前的问题是关于学习路线,可能用户希望有一个更详细的学习阶段划分,比如分阶段的学习路线,比如3到4个月的计划,或者3个阶段、4个步骤之类的。也有可能“3.4”是用户引用之前回答的某个点,但原回答中没有这样的编号,所以可能是误解。 接下来,需要推测用户的真实需求。用户可能希望得到一个结构化的学习计划,分阶段或分步骤,帮助他们系统地学习C++和算法,以应对刷题和实际应用(如CV、搜广推、机器人等)。因此,需要构建一个分阶段的学习路线,结合之前的优先级排序,给出每个阶段的目标、内容和时间建议。 在构建学习路线时,需要平衡C++语言特性和算法数据结构的学习,同时结合实践项目和应用方向的不同侧重点。还要考虑用户可能的背景,比如是否已有基础,时间安排等,但用户没有提供这些信息,所以需要保持通用性。 可能需要将学习路线分为几个阶段,比如基础阶段、进阶阶段、应用阶段,每个阶段包含语言和算法两方面的内容,并给出每个阶段的时间建议和学习资源。同时,结合之前提到的知识点优先级,确保重要的内容先学。 另外,用户提到的应用方向(CV、搜广推、机器人)各有不同,可能需要在不同阶段加入针对性的学习内容。例如,CV需要数值计算和图像处理,机器人需要多线程和实时系统,搜广推需要设计模式和网络通信。 最后,需要确保学习路线清晰,步骤明确,并鼓励用户实践和项目应用,以巩固知识。同时,提醒用户根据自身情况调整进度,保持持续学习和实践。</think>以下是针对 **C++刷题(/力扣)** 和 **算法应用(CV/搜广推/机器人)** 的 **分阶段学习路线**,结合核心知识点优先级和实践建议,分为 **3个阶段+4个专项突破方向**,总计约3-4个月(可根据基础调整): --- ### **阶段1:基础夯实(1-1.5个月)** #### **目标**:掌握C++核心语法基础算法,能解决力扣中等题。 1. **C++语法STL(2周)** - **重点**: - 容器(`vector`/`unordered_map`/`priority_queue`)的底层原理高频操作 - 算法(`sort`/`lower_bound`/`accumulate`)的灵活使用 - 迭代器Lambda表达式(简化自定义比较逻辑) - **实践**:手写`vector`简化,理解动态扩容机制。 2. **基础算法数据结构(3周)** - **必学内容**: - **算法**:二分查找、DFS/BFS、动态规划(背包/子序列)、贪心 - **数据结构**:链表、二叉树、哈希表、堆 - **刷题策略**: - 按「标签分类」刷题(如力扣“二叉树”专题),每天2-3题 - 优先解决高频题(如《剑指Offer》经典题)。 3. **调试优化(1周)** - **工具**: - GDB调试段错误,Valgrind排查内存泄漏 - 时间复杂度分析(避免TLE) - **技巧**:用`chrono`库计时,对比不同算法的实际性能。 --- ### **阶段2:进阶突破(1-1.5个月)** #### **目标**:掌握高阶算法工程能力,应对复杂场景。 1. **高阶算法(2周)** - **重点**: - 图论(最短路径/最小生成树) - 字符串处理(KMP/Trie树/AC自动机) - 动态规划优化(状态压缩/斜率优化) - **刷题**:提高组题目、力扣Hard题(如[LC 312. 戳气球](https://leetcode.cn/problems/burst-balloons/))。 2. **C++进阶特性(2周)** - **必学**: - 模板泛型编程(手写通用链表) - 多线程(`std::thread`/`std::mutex`) - 移动语义(右值引用/`std::move`) - **实践**:实现线程安全的队列模板,对比`std::move`复制的性能差异。 3. **领域工具链(2周)** - **CV方向**:OpenCV基础(图像读写/滤波)、Eigen矩阵运算 - **机器人方向**:ROS基础通信模型、多线程实时控制 - **搜广推方向**:设计模式(工厂/观察者)、HTTP请求(`libcurl`)。 --- ### **阶段3:实战专项(1-2个月)** #### **目标**:结合项目实战,深入特定领域。 1. **项目实战(3选1)** - **CV**:用C++实现图像边缘检测(Sobel算子) - **机器人**:模拟多传感器数据同步(线程+回调) - **搜广推**:实现简易LRU缓存(哈希表+双向链表)。 2. **竞赛面试强化(1周)** - **技巧**: - 学习Codeforces/的输入输出加速技巧 - 掌握「代码模板化」思路(如快速排序非递归) - **模拟面试**:限时解决力扣高频Hard题(如[LC 239. 滑动窗口最大值](https://leetcode.cn/problems/sliding-window-maximum/))。 --- ### **4个专项突破方向(可选)** 1. **并发编程**: - 学习`std::async`异步任务、原子操作(`std::atomic`) - 实战:用多线程加速归并排序。 2. **模板元编程**: - 掌握SFINAE、`constexpr`编译时计算 - 实战:实现编译期斐波那契数列。 3. **内存管理**: - 深入智能指针(`shared_ptr`控制块原理)、内存池设计 - 实战:手写简化内存池。 4. **算法优化**: - 学习SIMD指令集加速(如AVX2优化矩阵乘法) - 实战:对比普通循环SIMD本的性能差异。 --- ### **学习资源推荐** 1. **书籍**: - 《算法导论》(理论) + 《挑战程序设计竞赛》(实战) - 《Effective C++》《C++并发编程实战》 2. **在线平台**: - 力扣(按标签刷题)、(模拟竞赛场景) - Codeforces(训练思维速度和代码容错性) 3. **开源项目**: - OpenCV源码(学习C++工程化设计) - LevelDB(理解STL风格的内存管理数据结构)。 --- ### **关键原则** 1. **二八法则**:80%时间攻克高频考点(如动态规划、多线程),20%时间探索兴趣领域。 2. **反馈驱动**:每学完一个模块,用实际题目或项目验证效果(如学完DFS后刷岛屿问题)。 3. **领域交叉**:例如CV方向可将图像处理算法C++多线程结合,提升实时性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值