light oj 1427 AC自动机+dfs
Time Limit: 5 second(s) | Memory Limit: 128 MB |
A string is a finite sequence of symbols that are chosen from an alphabet. In this problem you are given a string T and n queries each with a stringPi, where the strings contain lower case English alphabets only. You have to find the number of times Pi occurs as a substring of T.
Input
Input starts with an integer T (≤ 10), denoting the number of test cases.
Each case starts with a line containing an integer n (1 ≤ n ≤ 500). The next line contains the string T (1 ≤ |T| ≤ 106). Each of the next nlines contains a string Pi (1 ≤ |Pi| ≤ 500).
Output
For each case, print the case number in a single line first. Then for each string Pi, report the number of times it occurs as a substring of T in a single line.
Sample Input |
Output for Sample Input |
2 5 ababacbabc aba ba ac a abc 3 lightoj oj light lit |
Case 1: 2 3 1 4 1 Case 2: 1 1 0 |
Notes
- Dataset is huge, use faster I/O methods.
- If S is a string then |S| denotes the length of S
建好字典树、构建好fail指针后,在树上走一遍主串,注意,只需要线性的走一遍就好,不需要走fail
然后建图:
每个点的fail指向的点向这个点建一条边,如果某个点被访问过,那么它的fail以及fail的fail。。。都访问过,所以这样建好图后直接dfs一遍,在回溯的时候把子树节点的访问次数加上来即可
另外,还要用一个hash[]标记每个单词在字典树中的位置的编号
dfs后,直接输出答案就好了
#include<cstdio> #include<cstring> #include<vector> using namespace std; const int MM = 500005,NC = 26; vector<int> edge[MM]; int N; char str[600]; int ans[600]; char s[1000010]; int hash[600]; struct trie{ int ch[NC],fail,f; void init(){ memset(ch,0,sizeof(ch)); fail=f=0; } }a[MM]; int cnt,rt,q[MM],front,last; void Init(){ cnt=1; rt=cnt++; a[0].init(); for(int i=0;i<NC;i++) a[0].ch[i]=rt; a[1].init(); } void Ins(char *in,int k){ int now=rt; for(;*in;++in){ int id=*in-'a'; if(!a[now].ch[id]){ a[cnt].init(); a[now].ch[id]=cnt++; } now=a[now].ch[id]; } hash[k]=now; } void build(){ front=last=0; q[front++]=rt; while(last<front){ int t=q[last++]; for(int i=0;i<NC;i++){ int tt=a[t].ch[i]; int ff=a[t].fail; if(a[t].ch[i]){ a[tt].fail=a[ff].ch[i]; q[front++]=tt; } else a[t].ch[i]=a[ff].ch[i]; } } } void AC(char *str){ int i=0,cur=rt; for(;str[i];i++){ int id=str[i]-'a'; cur=a[cur].ch[id]; a[cur].f++; } } void dfs(int u){ ans[u]=a[u].f; for(int i=0;i<edge[u].size();i++) { int v=edge[u][i]; dfs(v); ans[u]+=ans[v]; } } int main(){ int t,n,ca=1,i; scanf("%d",&t); while(t--){ Init(); scanf("%d",&n); scanf("%s",s); for(int i=0;i<n;i++){ scanf("%s",str); Ins(str,i); } build(); for(i=0;i<MM;i++) edge[i].clear(); for(i=1;i<cnt;i++) edge[a[i].fail].push_back(i); memset(ans,0,sizeof(ans)); AC(s); dfs(1); printf("Case %d:\n",ca++); for(i=0;i<n;i++) printf("%d\n",ans[hash[i]]); } return 0; }