poj4052 Hrinity
pdf题面:传送门
题目大意:给定一些单词和一个句子,问有多少个单词在句子中出现过,如果一个但单词包含另一个单词,并且两个单词都出现过,那么只算最外层的单词(包含另一个单词的单词).
分析:这道题如果没有第二个条件的话就和hdu2222是一模一样的题.但是没关系,可以先用hdu2222的方法找出所有出现过的单词,然后每个单词将它的子串给标记.如何找一个串的子串呢?如果一个字符串s[1......n],它的子串必定在s[1......r]和s[l......n]中,也就是在前缀和后缀中,在trie里,找前缀可以利用父亲节点.找后缀可以利用AC自动机的fail指针,这样递归地标记一下就可以了.
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int maxn = ,maxm = ;
char s[maxm],ss[maxm];
int T,n,cnt,tot = ,ans;
bool vis[maxn],tag[maxn],vis2[maxn]; void init()
{
n = cnt = ans = ;
memset(vis,false,sizeof(vis));
memset(vis2,false,sizeof(vis2));
memset(tag,false,sizeof(tag));
} struct node
{
int tr[],fail,id,fa;
void clear()
{
memset(tr,,sizeof(tr));
fail = id = fa = ;
}
} e[maxn]; void insert(int x)
{
int u = ;
for (int i = ; i <= cnt; i++)
{
int ch = ss[i] - 'A';
if (!e[u].tr[ch])
{
e[u].tr[ch] = ++tot;
e[tot].clear();
}
int temp = u;
u = e[u].tr[ch];
e[u].fa = temp;
}
e[u].id = x;
} void build()
{
queue <int> q;
for (int i = ; i < ; i++)
e[].tr[i] = ;
q.push();
while (!q.empty())
{
int u = q.front();
q.pop();
int fail = e[u].fail;
for (int i = ; i < ; i++)
{
int y = e[u].tr[i];
if (y)
{
e[y].fail = e[fail].tr[i];
q.push(y);
}
else
e[u].tr[i] = e[fail].tr[i];
}
}
} void dfs(int x)
{
if (tag[x])
return;
tag[x] = ;
vis[x] = ;
if (e[x].fail)
dfs(e[x].fail);
if (e[x].fa)
dfs(e[x].fa);
} bool ischar(char p)
{
return p >= 'A' && p <= 'Z';
} void getchange()
{
int len = strlen(s + );
cnt = ;
for (int i = ; i <= len; i++)
{
if (ischar(s[i]))
ss[++cnt] = s[i];
else
{
i++;
int res = ;
while (s[i] >= '' && s[i] <= '')
{
res = res * + s[i] - '';
i++;
}
char cc = s[i++];
while (res)
{
ss[++cnt] = cc;
res--;
}
}
}
} int main()
{
scanf("%d",&T);
while (T--)
{
init();
e[tot = ].clear();
scanf("%d",&n);
for (int i = ; i <= n; i++)
{
scanf("%s",s + );
getchange();
insert(i);
}
build();
scanf("%s",s + );
getchange();
int u = ;
for (int i = ; i <= cnt; i++)
{
int ch = ss[i] - 'A';
while (u && !e[u].tr[ch])
u = e[u].fail;
u = e[u].tr[ch];
int t = u;
while (t && !vis2[t])
{
vis2[t] = ;
if (e[t].id)
vis[t] = ;
t = e[t].fail;
}
} for (int i = ; i <= tot; i++)
if (!tag[i] && vis[i])
{
dfs(e[i].fail);
dfs(e[i].fa);
}
for (int i = ; i <= tot; i++)
if (vis[i])
ans++;
printf("%d\n",ans);
} return ;
}
poj4052 Hrinity的更多相关文章
- poj4052
题意:求一个文章(长度5.1e6)里面出现了多少个指定的模式串.重复出现只记一次.而且如果两个模式串都出现的情况下,一个是另一个的子串,则该子串不算出现过. 分析:AC自动机. 由于子串不算所以加一些 ...
- AC自动机-算法详解
What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...
随机推荐
- 搭建RTSP服务器时nginx的nginx.conf文件配置
worker_processes 1; events { worker_connections 1024;} http { include mime.types; default_type appli ...
- Boss直聘邮件通知小脚本
Boss 基于Python3的找工作利器--Boss直聘来消息邮件通知, 自动发送简历脚本,O(∩_∩)O~ 无聊写的,因为有时候觉得找工作心急如焚,想自动回复自动发简历啊有木有~~~ github地 ...
- EasyUI validatebox 自定义ajax验证用户名是否已存在
<td><input type="text" id="userName" name="userName" class=&q ...
- hadoop之Shuffle和Sort
MapRduce保证reducer的输入是按照key进行排过序的,原因和归并排序有关,在reducer接收到不同的mapper输出的有序数据后,需要再次进行排序,然后是分组排序,如果mapper输出的 ...
- python基础知识-04-字符串列表元组
python其他知识目录 内存,cpu,硬盘,解释器 实时翻译 编译器 :一次性翻译python2,3 除法,2不能得小数,3能得小数 1.字符串操作 1.1字符串操作startswith start ...
- JS 数组方法 array数组声明 元素的添加和删除 等
声明数组 var arr1 = [1,2,3,4,5]; var arr2 = new Array(100); //声明长度为100的arr2数组. arr2=[]; arr2.length = 10 ...
- 20181023-9 Alpha阶段第2周/共2周 Scrum立会报告+燃尽图 06
作业要求参见: https://edu.cnblogs.com/campus/nenu/2018fall/homework/2289 Scrum master:赵佳璐 一.小组介绍 组长:王一可 组员 ...
- 安装VS的过程
软件工程学习到第三周,我们需要下载一个新的软件,用来进行软件测试.刚开始知道的时候觉得没甚么,不就是下个软件吗!有什么大不了的,分分钟搞定的事.可是想象很美好,现实很骨感.这是一个巨大的工作量呀,不仅 ...
- Beta版软件使用说明
1引言 1 .1编写目的 编写本使用说明的目的是充分叙述本软件所能实现的功能及其运行环境,以便使用者了解本软件的使用范围和使用方法,并为软件的维护和更新提供必要的信息. 1 .2参考资料 1 .3术语 ...
- (Miller Rabin算法)判断一个数是否为素数
1.约定 x%y为x取模y,即x除以y所得的余数,当x<y时,x%y=x,所有取模的运算对象都为整数. x^y表示x的y次方.乘方运算的优先级高于乘除和取模,加减的优先级最低. 见到x^y/z这 ...