ZOJ3228 Searching the String(AC自动机)

时间:2021-03-05 06:00:14

题目大概是给一个主串,询问若干个模式串出现次数,其中有些模式串要求不能重叠。

对于可以重叠的就是一个直白的多模式匹配问题;而不可重叠,在匹配过程中贪心地记录当前匹配的主串位置,然后每当出现一个新匹配根据记录的位置判断这个新匹配是否成立,最后更新位置。

另外,考虑到数据可以出现多个模式串相同的情况,实现要做一些处理:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #include<algorithm>
 5 using namespace std;
 6 #define MAXN 666666
 7 //-1 none, 0 overlap, 1 not, 2 both
 8 int tn,ch[MAXN][26],fail[MAXN],flag[MAXN],len[MAXN];
 9 int insert(char *s,int k){
10     int x=0,l=0;
11     for(int i=0; s[i]; ++i){
12         int y=s[i]-'a';
13         if(ch[x][y]==0) ch[x][y]=++tn;
14         x=ch[x][y];
15         ++l;
16     }
17     len[x]=l;
18     if(flag[x]==-1) flag[x]=k;
19     else if(flag[x]==0 && k==1) flag[x]=2;
20     else if(flag[x]==1 && k==0) flag[x]=2;
21     return x;
22 }
23 void getfail(){
24     memset(fail,0,sizeof(flag));
25     queue<int> que;
26     for(int i=0; i<26; ++i){
27         if(ch[0][i]) que.push(ch[0][i]);
28     }
29     while(!que.empty()){
30         int x=que.front(); que.pop();
31         for(int i=0; i<26; ++i){
32             if(ch[x][i]){
33                 que.push(ch[x][i]);
34                 fail[ch[x][i]]=ch[fail[x]][i];
35             }else ch[x][i]=ch[fail[x]][i];
36         }
37     }
38 }
39 int last[MAXN],ans[2][MAXN],first[111111],second[111111];
40 char str[111111];
41 void query(){
42     int x=0;
43     for(int i=0; str[i]; ++i){
44         int y=str[i]-'a';
45         int tmp=x=ch[x][y];
46         while(tmp){
47             if(flag[tmp]!=-1 && flag[tmp]!=1) ++ans[0][tmp];
48             if(flag[tmp]!=-1 && flag[tmp]!=0){
49                 if(last[tmp]==-1 || i-last[tmp]>=len[tmp]){
50                     last[tmp]=i;
51                     ++ans[1][tmp];
52                 }
53             }
54             tmp=fail[tmp];
55         }
56     }
57 }
58 int main(){
59     int n,cse=0;
60     char s[11];
61     while(~scanf("%s",str)){
62         tn=0;
63         memset(ch,0,sizeof(ch));
64         memset(flag,-1,sizeof(flag));
65         scanf("%d",&n);
66         for(int i=0; i<n; ++i){
67             scanf("%d%s",&first[i],s);
68             second[i]=insert(s,first[i]);
69         }
70         getfail();
71         memset(ans,0,sizeof(ans));
72         memset(last,-1,sizeof(last));
73         query();
74         printf("Case %d\n",++cse);
75         for(int i=0; i<n; ++i){
76             printf("%d\n",ans[first[i]][second[i]]);
77         }
78         putchar('\n');
79     }
80     return 0;
81 }