其实本题比HDU的病毒侵袭1还简单,不过有一个陷阱卡到我了:就是搜索text的时候,当遇到的字母不是大写字母的时候,那么就要重新从根节点开始搜索,否则就会答案错误。
那么一点陷阱,居然没想到啊。
教训啊:看来对不太平常的地方,需要更加深入的思考,才能发现其中的陷阱,否则就WA了。
#include <stdio.h>
#include <string.h>
#include <queue>
using std::queue;
const int MAX_N = 1001;
const int VIRUS_LEN = 51;
const int TXT_LEN = 2000001;
const int ARR_SIZE = 26;
char Virus[MAX_N][VIRUS_LEN], txt[TXT_LEN];
int IdNum[MAX_N];
inline int getIndex(char a) { return a - 'A'; }
struct Node
{
int n, num;
Node *fail;
Node *arr[ARR_SIZE];
};
Node pool[MAX_N*VIRUS_LEN], *Trie;
int poolID;
void clearNode(Node *rt)
{
rt->n = rt->num = 0;
rt->fail = NULL;
memset(rt->arr, 0, sizeof(rt->arr));
}
void insert(char *w, int num)
{
Node *pCrawl = Trie;
for ( ; *w; w++)
{
int id = getIndex(*w);
if (!pCrawl->arr[id])
{
pCrawl->arr[id] = &pool[poolID++];
clearNode(pCrawl->arr[id]);
}
pCrawl = pCrawl->arr[id];
}
pCrawl->n++;
pCrawl->num = num;
}
void buildFail()
{
queue<Node *> qu;
qu.push(Trie);
while (!qu.empty())
{
Node *pCrawl = qu.front(); qu.pop();
for (int i = 0; i < ARR_SIZE; i++)
{
if (!pCrawl->arr[i]) continue;
pCrawl->arr[i]->fail = Trie;
Node *fail = pCrawl->fail;
while (fail)
{
if (fail->arr[i])
{
pCrawl->arr[i]->fail = fail->arr[i];
break;
}
fail = fail->fail;
}
qu.push(pCrawl->arr[i]);
}
}
}
void search()
{
Node *pCrawl = Trie;
for (char *p = txt; *p; p++)
{
if (*p < 'A' || 'Z' < *p)
{
pCrawl = Trie;
continue;
}
int id = getIndex(*p);
while (!pCrawl->arr[id] && pCrawl != Trie) pCrawl = pCrawl->fail;
if (pCrawl->arr[id])
{
pCrawl = pCrawl->arr[id];
for (Node *tmp = pCrawl; tmp && tmp->n; tmp = tmp->fail)
{
if (tmp->n) IdNum[tmp->num]++;
}
}
}
}
int main()
{
int n;
Trie = &pool[0];
while (scanf("%d", &n) != EOF)
{
getchar();
clearNode(Trie);
poolID = 1;
for (int i = 0; i < n; i++)
{
gets(Virus[i]);
insert(Virus[i], i);
}
buildFail();
memset(IdNum, 0, sizeof(int) * n);
gets(txt);
search();
for (int i = 0; i < n; i++)
{
if (IdNum[i]) printf("%s: %d\n",Virus[i], IdNum[i]);
}
}
return 0;
}