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用来在一篇文章中匹配一个模式串:但 ...
随机推荐
- SQL Server变量杂谈
学习SQL的过程有进步的话还是一件很美妙的事情的 在第一家公司虽然只呆了两年,但是感觉是我进步最快的两年.那时候工作和生活都挺充实的,每天都有一点点的收获和付出,其中最大的收获莫过于掌握一些核心技能. ...
- 【RL系列】马尔可夫决策过程——Jack‘s Car Rental
本篇请结合课本Reinforcement Learning: An Introduction学习 Jack's Car Rental是一个经典的应用马尔可夫决策过程的问题,翻译过来,我们就直接叫它“租 ...
- kylin-note
http://www.cnblogs.com/tgzhu/category/915975.html https://sdk.cn/news/3566 https://www.linuxidc.com/ ...
- [C++] Solve "No source available for main()" error when debugging on Eclipse
In Mac, the issue image: 1. A existing cmake project on disk 2. import this project into Eclipse. 3 ...
- border、margin、padding三者的区别
当你写前端的时候,肯定会遇到border,margin和padding这几个单词. 如: padding: 16px 0; margin: 0 10px; 在CSS中,他们是表示距离的东西,很多人刚开 ...
- 20162316刘诚昊 第八周实验报告:实验二 Java面向对象程序设计
实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验要求 1.没有Linux基础的同学建议先学习<L ...
- sql nolock是什么
百度:SQL Server 中的 NOLOCK 到底是什么意思? 文章地址:http://blog.sina.com.cn/s/blog_7d3b18a50100rfwg.html 查询语句加上 no ...
- [图算法] 1003. Emergency (25)
As an emergency rescue team leader of a city, you are given a special map of your country. The map s ...
- ElasticSearch API 简要介绍
调用其API会返回很多信息,例如集群的信息,节点的信息等 检查集群的状态----Restful API说明 1:检查集群状态信息 2:管理集群 3:执行 增删改查 命令 4:执行高级命令 Restfu ...
- 更改HTTP头信息
http信息分三部分 1.请求行 GET lizi.php HTTP/1.1 2.HTTP头信 Host: localhost Connection: keep-alive Cache-Contr ...