明明题目没有说多组数据, 然后我就当作一组数据来做了。
看来看去代码都没有错,但是一提交就WA,害我该了一个下午。天啊!
去找题解才知道是多组数据。不要被省略”有多组数据“而欺骗了。
/*
题意:中文题,详见HDU 3065
思路:套AC自动机模板。
注意:建trie树时,字符串的信息(病毒编号)存放在最后一个字母的
value中,病毒特征码只包含“英文大写字符”,所以孩子节点只需26个
没遇到一种病毒,则把(病毒出现次数的)数组对应的值+1。
*/
#include<iostream>
#include<cstring>
#include<queue>
#include<ctype.h>
using namespace std;
const int MAXM=2000100;//网站长度
const int MAXN=50010;//病毒最多的需要的节点数
char web[MAXM];//网站串
char virus[1010][55];//病毒存放的数组
int virusN[1010];//对应位置病毒出现的次数
struct trie
{
int root,trieN;//根节点和当前树的最大节点
int child[MAXN][26],value[MAXN],fail[MAXN];//孩子节点,节点值,失配数组
int NewTrie()//新建节点
{
value[trieN]=0;
memset(child[trieN],-1,sizeof(child[trieN]));
return trieN++;
}
void init()//初始化
{
trieN=0;
root=NewTrie();
}
void Insert(char s[],int k)//建树
{
int x=root;
for(int i=0;s[i];i++)
{
if(child[x][s[i]-'A']==-1)
{
child[x][s[i]-'A']=NewTrie();
}
x=child[x][s[i]-'A'];
}
value[x]=k;//对应信息存放到最后一个字母中
}
void Build()//构建fail数组
{
int x;
queue<int> q;
fail[root]=root;
for(int i=0;i<26;i++)
{
if(child[root][i]==-1)
{
child[root][i]=root;
}
else
{
fail[child[root][i]]=root;
q.push(child[root][i]);
}
}
while(!q.empty())
{
x=q.front();q.pop();
for(int i=0;i<26;i++)
{
if(child[x][i]==-1)
{
child[x][i]=child[fail[x]][i];
}
else
{
fail[child[x][i]]=child[fail[x]][i];
q.push(child[x][i]);
}
}
}
}
void query(char s[])//网站匹配
{
int x=root,temp;
for(int i=0;web[i];i++)
{
if(!isupper(web[i]))//因为网站中字符都是ASCII码可见字符,而
{ //病毒只有大写字母,所以如果不是大写字母则
x=0; //可忽略,也可预处理先把web里面非大写字母去掉
continue;
}
x=temp=child[x][s[i]-'A'];
while(temp!=root)
{
if(value[temp])//存在这种病毒
{
virusN[value[temp]]++;//对应位置+1
}
temp=fail[temp];
}
}
}
}ac;
int main()
{
int n;
while(cin>>n)
{
ac.init();//初始化
memset(virusN,0,sizeof(virusN));
for(int i=1;i<=n;i++)
{
cin>>virus[i];
ac.Insert(virus[i],i);//建树
}
ac.Build();//构造fail
getchar();
cin.getline(web,MAXM);//输入网站,可能包含空格等
ac.query(web);//匹配
for(int i=1;i<=n;i++)
{
if(virusN[i])//初始为0,只要出现过这种病毒则>0
{
cout<<virus[i];
cout<<": "<<virusN[i]<<endl;
}
}
}
return 0;
}