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的更多相关文章

  1. poj4052

    题意:求一个文章(长度5.1e6)里面出现了多少个指定的模式串.重复出现只记一次.而且如果两个模式串都出现的情况下,一个是另一个的子串,则该子串不算出现过. 分析:AC自动机. 由于子串不算所以加一些 ...

  2. AC自动机-算法详解

    What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...

随机推荐

  1. 001----Mysql隔离级别

    一:事务隔离级别 mysql数据库的隔离界别如下: 1, READ UNCOMMITTED(未提交读) 事务中的修改,即使没有提交,对其它事务也是可见的.  这样会造成脏读(Dirty Read)的问 ...

  2. mac 的一些使用技巧

    1. mac有一个自带的服务器环境, 目录路径 /Library/WebServer/Documents 打开终端  a. 启动 sudo apachectl start b. 重新启动 sudo a ...

  3. mysql数据库查询

    查询数据指从数据库中获取所需要的数据.查询数据是数据库操作中最常用,也是最重要的操作.用户可以根据自己对数据的需求,使用不同的查询方式.通过不同的查询方式,可以获得不同的数据.MySQL中是使用SEL ...

  4. 20181016-4 Alpha阶段第1周/共2周 Scrum立会报告+燃尽图 02

    此次作业要求参见 [https://edu.cnblogs.com/campus/nenu/2018fall/homework/2247] Scrum master:祁玉 一.小组介绍 组长:王一可 ...

  5. 软件工程第七周psp

    1.PSP表格 类别 任务 开始时间 结束时间 中断时间 delta时间 立会 汇报昨天的成绩,分配任务,部署计划 10月27日18:00 10月27日18:36 0 36分钟 准备工作 查阅有关资料 ...

  6. P4语法(3)Table,Action

    Table table是p4的匹配——动作表,定义了匹配字段(key).动作(action)和一些其他相关属性. 其处理数据包的流程: Key construction.建立其匹配字段 Key loo ...

  7. HDU 5428 The Factor 分解因式

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5428 The Factor  Accepts: 101  Submissions: 811  Tim ...

  8. jQuery之元素查找

    在已经匹配出的元素集合中根据选择器查找孩子/父母/兄弟标签1. children(): 子标签中找2. find() : 后代标签中找3. parent() : 父标签4. prevAll() : 前 ...

  9. 第七次java作业

     interface Pet{public String getName();public String getColor();public int getAge();}class Cat imple ...

  10. 第二周:Scrum Meeting

    一.站立会议 顾名思义,站立会议即是在敏捷开发的冲刺阶段,为了更好地平衡团队成员的“交流”和“集中注意力”之间的矛盾.通过每日例会,即团队成员通过面对面的交流,并且其中大多数团队成员站着对会议进行讨论 ...