poj4052
题意:求一个文章(长度5.1e6)里面出现了多少个指定的模式串。重复出现只记一次。而且如果两个模式串都出现的情况下,一个是另一个的子串,则该子串不算出现过。
分析:AC自动机。
由于子串不算所以加一些特殊处理:
1.在文章匹配过程中,如果出现了一个模式串我们不是把匹配数量+1,而是记录那个出现过vis[id] = true;,当然trie树种也是记录了模式串的id。
2.在匹配结束后,我们遍历所有出现过的模式串,在Trie树种找到其所有出现过的子串并将其标为未出现过vis[id] = false;
要如何查找子串呢?
只需要记录每个出现过的串所对应的Trie树中的节点位置,由该节点向上走到root。其间走过的每个节点都沿着fail指针走到root一次。这样二重循环遍历到的所有节点就对应了Trie中所有该模式串的子串。
因为在AC自动机中父节点指针就是找前缀,fail指针就是找后缀。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cctype>
using namespace std; #define D(x)
const int MAX_LEN = (int)(5.1e6) + ;
const int MAX_N = ;
const int MAX_FINGER_LEN = ;
const int MAX_CHILD_NUM = ;
const int MAX_NODE_NUM = MAX_N * MAX_FINGER_LEN; int n;
char st[MAX_LEN];
char st2[MAX_LEN];
int vis[MAX_N];
bool check[MAX_NODE_NUM]; struct Trie
{
int next[MAX_NODE_NUM][MAX_CHILD_NUM];
int fail[MAX_NODE_NUM];
int count[MAX_NODE_NUM];
int father[MAX_NODE_NUM];
int node_cnt;
int root; void init()
{
node_cnt = ;
root = newnode();
} int newnode()
{
for (int i = ; i < ; i++)
next[node_cnt][i] = -;
count[node_cnt++] = ;
return node_cnt - ;
} int get_id(char a)
{
return a - 'A';
} void insert(char buf[], int index)
{
int len = strlen(buf);
int now = root;
for (int i = ; i < len; i++)
{
int id = get_id(buf[i]);
if (next[now][id] == -)
{
next[now][id] = newnode();
father[next[now][id]] = now;
}
now = next[now][id];
}
count[now] = index;
} void build()
{
queue<int>Q;
fail[root] = root;
father[root] = root;
for (int i = ; i < ; i++)
if (next[root][i] == -)
next[root][i] = root;
else
{
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
while (!Q.empty())
{
int now = Q.front();
Q.pop();
for (int i = ; i < ; i++)
if (next[now][i] == -)
next[now][i] = next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
} int query(char buf[])
{
int now = root;
int res = ;
for (int i = ; buf[i]; i++)
{
now = next[now][get_id(buf[i])];
int temp = now;
while (temp != root && !check[temp])
{
if (count[temp] != )
vis[count[temp]] = temp;
check[temp] = true;
temp = fail[temp];
}
}
return res;
} void debug()
{
for(int i = ;i < node_cnt;i++)
{
printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],count[i]);
for(int j = ;j < ;j++)
printf("%2d",next[i][j]);
printf("]\n");
}
} void cal()
{
for (int i = ; i <= n; i++)
{
if (vis[i] == )
{
continue;
}
int temp = vis[i];
while (temp != root)
{
int temp2 = temp;
while (temp2 != root && !check[temp2])
{
if (count[temp2] != && count[temp2] != i)
{
vis[count[temp2]] = ;
check[temp2] = true;
}
temp2 = fail[temp2];
}
temp = father[temp];
}
}
}
}; Trie ac; void transform(char st[], char st2[])
{
int len = ;
for (int i = ; st[i]; i++)
{
if (isupper(st[i]))
{
st2[len++] = st[i];
continue;
}
i++;
int temp = ;
while (isdigit(st[i]))
{
temp *= ;
temp += st[i] - '';
i++;
}
for (int j = ; j < temp; j++)
{
st2[len + j] = st[i];
}
len += temp;
i++;
}
st2[len] = ;
} void input()
{
scanf("%d", &n);
for (int i = ; i <= n; i++)
{
scanf("%s", st);
transform(st, st2);
ac.insert(st2, i);
}
} int work()
{
memset(vis, , sizeof(vis));
memset(check, , sizeof(check));
ac.query(st2);
memset(check, , sizeof(check));
ac.cal();
int ret = ;
for (int i = ; i <= n; i++)
{
if (vis[i])
{
D(printf("#%d\n", vis[i]));
ret++;
}
}
return ret;
} int main()
{
int t;
scanf("%d", &t);
while (t--)
{
ac.init();
input();
ac.build();
scanf("%s", st);
transform(st, st2);
printf("%d\n", work());
}
return ;
}
poj4052的更多相关文章
- poj4052 Hrinity
pdf题面:传送门 题目大意:给定一些单词和一个句子,问有多少个单词在句子中出现过,如果一个但单词包含另一个单词,并且两个单词都出现过,那么只算最外层的单词(包含另一个单词的单词). 分析:这道题如果 ...
随机推荐
- “Transaction rolled back because it has been marked as rollback-only”
spring的声明事务提供了强大功能,让我们把业务关注和非业务关注的东西又分离开了.好东西的使用,总是需要有代价的.使用声明事务的时候,一 个不小心经常会碰到“Transaction rolled b ...
- poj3254 Corn Fields (状压DP)
http://poj.org/problem?id=3254 Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissio ...
- 解决英文或数字在HTMl网页中不自动换行。
对于网页设计的新手而言,在接触一段时间的HTML/CSS后,一定会遇到这样的问题:对于已经定义了宽度的容器(如DIV,TD,段落等)如果里面出现了较长的英文或数字,则内容不能自动换行然后会将框架撑出设 ...
- 从一个弱引用导致的奔溃 谈 weak assign strong的应用场景【iOS开发教程】
从一个弱引用导致的奔溃 谈 weak assign strong的应用场景 .h中的定义方法一: @property (nonatomic, assign) NSArray *dataSource; ...
- UI第三节——UIView详解
- (void)viewDidLoad { [super viewDidLoad]; UIView *redView = [[UIView alloc] initWithFrame:CGRectMak ...
- Spring配置bean文件的底层实现方式
首先 bean文件如下: <beans> <bean id="date" class="java.util.Date"></bea ...
- 大数据之pig 命令
1.pig与hive的区别 pig和hive比较类似的,都是类sql的语言,底层都是依赖于hadoop 走的mapreduce任务. pig和hive的区别就是,想要实现一个业务逻辑的话, ...
- springmvc之log4j
1.工程结构 2.所需jar包 3.web.xml <?xml version="1.0" encoding="UTF-8"?> <web-a ...
- PowerDesigner的使用(一)
一. PowerDesigner 功能 1. 需求管理:记录需求,分析设计模型 2. 生成文档:生成HTML格式文档,方便沟通. 3. 影响度分析:模型之间连接起来,同步修改功能. 4. 数据映射:提 ...
- .net生成二维码
下好QRCode.dll引用到项目中 using System; using System.Collections.Generic; using System.Linq; using System.W ...