Description

小t非常感谢大家帮忙解决了他的上一个问题。然而病毒侵袭持续中。在小t的不懈努力下,他发现了网路中的“万恶之源”。这是一个庞大的病毒网站,他有着好多好多的病毒,但是这个网站包含的病毒很奇怪,这些病毒的特征码很短,而且只包含“英文大写字符”。当然小t好想好想为民除害,但是小t从来不打没有准备的战争。知己知彼,百战不殆,小t首先要做的是知道这个病毒网站特征:包含多少不同的病毒,每种病毒出现了多少次。大家能再帮帮他吗?
 

Input

第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1―50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。 
 

Output

按以下格式每行一个,输出每个病毒出现次数。未出现的病毒不需要输出。 
病毒特征码: 出现次数 
冒号后有一个空格,按病毒特征码的输入顺序进行输出。 
 

Sample Input

3 AA BB CC ooxxCC%dAAAoen....END
 

Sample Output

AA: 2 CC: 1

Hint

 Hit: 题目描述中没有被提及的所有情况都应该进行考虑。比如两个病毒特征码可能有相互包含或者有重叠的特征码段。 计数策略也可一定程度上从Sample中推测。 
         
 

需要靠谱的模板

orz

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int NODE=500010;
#define FF(i,a) for(int i=0;i<a;i++)
#define id(c) c-'A'
int chd[NODE][26],word[NODE],fail[NODE],sz,ans[1100];
char s1[1100][550],s2[2000200];
void Ins(char *s,int val)
{
    int p=0;
        for(;*s;s++)
        {
            if(!chd[p][id(*s)])
            {
                memset(chd[sz],0,sizeof(chd[sz]));
                word[sz]=0;
                chd[p][id(*s)]=sz++;
            }
            p=chd[p][id(*s)];
        }
    word[p]=val;
}
int Que[NODE];
void AC()
{
    int *s=Que,*e=Que;
    FF(i,26) if(chd[0][i])
    {
        fail[chd[0][i]]=0;
        *e++=chd[0][i];
    }
    while(s!=e)
    {
        int p=*s++;
        FF(i,26)
        if(chd[p][i])
        {
            int k=chd[p][i];
            fail[k]=chd[fail[p]][i];
            *e++=k;
        }
        else chd[p][i]=chd[fail[p]][i];
    }
}
void search(char *s)
{
    int p=0,sum=0;
    for(;*s;s++)
    {
        if(!isupper(*s)){p=0;continue;}
        p=chd[p][id(*s)];
        for(int tmp=p;tmp>0;tmp=fail[tmp])
            if(word[tmp]) ans[word[tmp]]++;
    }
}

int main()
{
   // freopen("cin.txt","r",stdin);
    int n;
    fail[0]=0;
    while(~scanf("%d",&n))
    {
        getchar();
        memset(chd[0],0,sizeof(chd[0]));
        memset(ans,0,sizeof(ans));
        sz=1;
        for(int i=0;i<n;i++)
        {
            scanf("%s",s1[i]);
            Ins(s1[i],i+1);
        }
        AC();
        scanf("%s",s2);
        search(s2);
        FF(i,n)
        if(ans[i+1])
        printf("%s: %d\n",s1[i],ans[i+1]);
    }
    return 0;
}