hdu5384(trie树)
给定n个字符串Ai
给定m个字符串Bi
问所有的Bi在每个Ai中出现了多少次
很显然,对Bi建Trie图,然后每次用Ai去匹配的时候,不断查找当前匹配串的最长后缀,这样就能找到答案了
比赛的时候也这样水过了。(又一次我认为这样不会过,但是交上去却过了)
如有有这样的数据的话
1
1 1
10^5个a
10^5个a
那么时间复杂度是10^10,
其实上面不断查找当前匹配串的最长后缀是没必要的,是重复操作的。
如果我们知道当前匹配串的最长后缀包含了多少个Bi,那么就不用去不断回溯了。
所以我们只要在构建fail指针的时候,处理处当前fail指针指向的字符串包含了多少个Bi,那么就不用不断的回溯了。
(哈哈,学到东西了)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/* */
const int N = + ;
struct Node
{
int fail, next[];
int cnt;
void init()
{
fail = -;
cnt = ;
for (int i = ; i < ; ++i)
next[i] = -;
}
}Trie[N];
int size;
void insert(int root, char *str)
{
int idx, cur = root;
for (int i = ; str[i]; ++i)
{
idx = str[i] - 'a';
if (Trie[cur].next[idx] == -)
{
Trie[size].init();
Trie[cur].next[idx] = size++;
}
cur = Trie[cur].next[idx];
}
Trie[cur].cnt++;
}
void makeFail(int root)
{
queue<int> q;
for (int i = ; i < ; ++i)
{
if (Trie[root].next[i] == -)
Trie[root].next[i] = root;
else
{
Trie[Trie[root].next[i]].fail = root;
q.push(Trie[root].next[i]);
}
}
while (!q.empty())
{
int cur = q.front();
q.pop();
for (int i = ; i < ; ++i)
{
if (Trie[cur].next[i] == -)
{
Trie[cur].next[i] = Trie[Trie[cur].fail].next[i];
}
else
{
Trie[Trie[cur].next[i]].fail = Trie[Trie[cur].fail].next[i];
//处理处,当前fail指针指向的字符串包含了多少个Bi
Trie[Trie[cur].next[i]].cnt += Trie[Trie[Trie[cur].fail].next[i]].cnt;
q.push(Trie[cur].next[i]);
} }
}
}
int match(int root, char *str)
{
int i = ;
int idx;
int cur = root;
int ret = ;
while (str[i])
{
idx = str[i] - 'a';
cur = Trie[cur].next[idx];
//int tmp = cur;
//while (tmp != root)
//{
// ret += Trie[tmp].cnt;
// tmp = Trie[tmp].fail;
//} ret += Trie[cur].cnt;
i++;
}
return ret;
}
/*
题目问所有的Bi在每一个Ai中出现的次数 一个串的所有子串可以表示为它所有前缀的后缀
对所有的Bi建trie图
我们可以让每个Ai匹配的时候,就让这个当前字符串不断的去寻找最长后缀,
时间复杂度吵了
,然而数据水,居然过了
*/ char str[];
char str2[];
int main()
{
int t, n, m;
//freopen("d:/in.txt", "r", stdin);
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &m);
int idx = ;
size = ;
Trie[].init();
Trie[].fail = ;
for (int i = ; i < n; ++i)
{
scanf("%s", str + idx);
idx += strlen(str + idx) + ;
}
for (int i = ; i < m; ++i)
{
scanf("%s", str2);
insert(,str2);
}
makeFail();
idx = ;
for (int i = ; i < n; ++i)
{
printf("%d\n", match(, str + idx));
idx += strlen(str + idx) + ;
}
}
return ;
}
hdu5384(trie树)的更多相关文章
- 基于trie树做一个ac自动机
基于trie树做一个ac自动机 #!/usr/bin/python # -*- coding: utf-8 -*- class Node: def __init__(self): self.value ...
- 基于trie树的具有联想功能的文本编辑器
之前的软件设计与开发实践课程中,自己构思的大作业题目.做的具有核心功能,但是还欠缺边边角角的小功能和持久化数据结构,先放出来,有机会一点点改.github:https://github.com/chu ...
- hihocoder-1014 Trie树
hihocoder 1014 : Trie树 link: https://hihocoder.com/problemset/problem/1014 题意: 实现Trie树,实现对单词的快速统计. # ...
- 洛谷P2412 查单词 [trie树 RMQ]
题目背景 滚粗了的HansBug在收拾旧英语书,然而他发现了什么奇妙的东西. 题目描述 udp2.T3如果遇到相同的字符串,输出后面的 蒟蒻HansBug在一本英语书里面找到了一个单词表,包含N个单词 ...
- 通过trie树实现单词自动补全
/** * 实现单词补全功能 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #incl ...
- #1014 Trie树
本题主要是求构造一棵Trie树,即词典树用于统计单词. C#代码如下: using System; using System.Collections.Generic; using System.Lin ...
- Trie树-字典查找
描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一本词典,于是小Hi就向小Ho提出了那个经典的问题: ...
- Trie树的创建、插入、查询的实现
原文:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=28977986&id=3807947 1.什么是Trie树 Tr ...
- Trie树(c++实现)
转:http://www.cnblogs.com/kaituorensheng/p/3602155.html http://blog.csdn.net/insistgogo/article/detai ...
- [转]双数组TRIE树原理
原文名称: An Efficient Digital Search Algorithm by Using a Double-Array Structure 作者: JUN-ICHI AOE 译文: 使 ...
随机推荐
- jsp获得本地及serverIP的方法
InetAddress addr = InetAddress.getLocalHost(); String ip = addr.getHostAddress().toString();//获得本机IP ...
- oracle触发器中增删改查本表
oracle触发器中增删改查本表 (1)只有before insert触发器中才可以查询或更新本表 create or replace trigger tri_test_ins before inse ...
- win32 sdk树形控件的项拖拽实现
本课中,我们将学习如何使用树型视图控件.另外还要学习如何在树型视图中完成拖-拉动作,以及如何使用图象列表. 理论: 树型视图是一种特别的窗口,我们可以使用它一目了然地表示某种层次关系.譬如象在资源管理 ...
- Hibernate @Embeddable注解
在hibernate中实现自己定义类型,仅仅要实现UserType接口就可以或者以Component的形式提供.JPA的@Embedded有点类似,通过此凝视能够在你的Entity中使用一般的java ...
- Swift - 多行文本输入框(UITextView)的用法
1,多行文本控件的创建 1 2 3 4 var textview=UITextView(frame:CGRectMake(10,100,200,100)) textview.layer.borderW ...
- Android监听外部存储设备的状态(SD卡、U盘等等)
近期在项目中须要对外部存储设备的状态进行监听,所以整理了此笔记,以便日后查看. 外部存储设备的状态变化时发出的广播 对照不同状态下的广播 1. 插入外部SD卡时: 2. 移除外部SD卡时: 3. 连接 ...
- 【IOS实例小计】图像移动--可扩展为动态实现图标变化
预备知识: 1.页面切换: 从一个ViewController切换到另一个ViewController有下面几种方法: (1)self.view addSubview:(加载的新页面); 相 ...
- extjs desktop startmenu (開始菜单)
extjs desktop 的開始菜单 二级菜单,仅仅是简单演示实现原理,如 须要动态生成,自己改造就可以,下面基本方法原理: 首先 建立一个js文件 生成開始菜单数据: function Get ...
- Eclipse 每次打开workspace目录记录位置?
E:\eclipse_j2ee eclipse安装根目录 在这个文件下: E:\eclipse_j2ee\configuration\.settings\org.eclipse.ui.ide.pref ...
- XML语法规范
1: 怎样声明一个xml文件 答:由2部分组成 声明部分,声明xml的版本号与编码(版本号仅仅有1.0) <? xml version="1.0" encoding=&quo ...