这个题断断续续写了一星期,借鉴了大神的思路,总算是把这个题A掉了。
题意就是在文本中找到第一个字典中的单词,很明显的AC自动机,但是卡内存和卡时间。
卡时间的话,网上有的自动机的模板是会超时的。不过大致算法是一样的,只是有个小细节要处理。
卡内存,网上大神的题解用了map,简单易懂,我为了最大限度的保存空间,用的结构体指针的形式,对于任意一个节点,
它的儿子节点都用map将int映射成一个节点指针,这样整个树的构建便是全动态的(~似乎内存占用还是很大)。
但是如此,还是会MLE,借鉴了大神的思路,把单词分段,每次只插入一定量的单词,然后从树中查找匹配。
开始MLE了,是因为没有每次插入的时候没有删除整个树,写了递归删树之后这题便AC了~
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <set>
#include <queue>
#include <map>
using namespace std;
const int maxm = 100010;
struct Node{
int point;
Node *fail;
map<int, Node *> child;
Node() {
fail = NULL;
child.clear();
point = -1;
}
} *root, *Q[maxm];
void Insert(string &s, int num){
Node *p = root;
int len = s.size();
for(int i = 0; i < len; ++i){
int id = s[i];
if(!p->child.count(id)){
p->child[id] = new Node;
}
p = p->child[id];
if(i == len - 1) p->point = num;
}
}
const int maxn = 10000 + 10;
int slen[maxn];
void BuildFailPoint(){
int front = 0, rear = 1;
Q[1] = root;
while(front < rear){
Node *now = Q[++front];
map<int, Node *>::iterator it = now->child.begin();
for(;it != now->child.end();++it){
int id = it->first;
if(now == root) it->second->fail = root;
else{
Node *p = now->fail;
while(p != NULL){
if(p->child.count(id)) {
it->second->fail = p->child[id];
break;
}
p = p->fail;
}
if(p == NULL) it->second->fail = root;
if(it->second->point == -1 || it->second->fail->point != -1
&& slen[it->second->point] < slen[it->second->fail->point]){
it->second->point = it->second->fail->point;
}
}
Q[++rear] = it->second;
}
}
}
int Query(const string & str){
int Min = 0x3f3f3f3f;
int len = str.size();
Node *p = root;
for(int i = 0; i < len; ++i) {
int id = str[i];
while(p != root && !p->child.count(id)) p = p->fail;
if(p->child.count(id))
p = p->child[id];
if(p->point != -1) {
Min = min(Min, i - slen[p->point] +2);
}
}
return Min;
}
void delete_node(Node *root){
if(root == NULL) return;
for(map<int, Node *>::iterator it = root->child.begin(); it != root->child.end(); ++it){
delete_node(it->second);
}
delete root;
}
string s;
vector<string> words;
vector<string> text;
int main()
{
root = new Node;
int n; scanf("%d", &n); getchar();
for(int i = 0; i < n; ++i){
getline(cin, s);
words.push_back(s);
slen[i] = s.size();
}
int m;
scanf("%d", &m); getchar();
for(int i = 0; i < m; ++i) {
getline(cin,s);
text.push_back(s);
}
int i = 0;
const int inf = 0x3f3f3f3f;
int col = inf;
int Min = inf;
while(i < n){
int tot = 0;
delete_node(root);
root = new Node;
for(;i < n && slen[i] + tot < maxn * 5; ++ i){
Insert(words[i], i);
tot+= slen[i];
}
BuildFailPoint();
for(int i = 0; i < m; ++i){
int res = Query(text[i]);
if(res != inf){
if(i < col){
col = i;
Min = res;
}else if(i == col && res < Min){
Min = res;
}
}
}
}
if(Min == inf){
printf("Passed\n");
}else{
printf("%d %d\n",col + 1, Min);
}
return 0;
}