题目大概是给一个主串,询问若干个模式串出现次数,其中有些模式串要求不能重叠。
对于可以重叠的就是一个直白的多模式匹配问题;而不可重叠,在匹配过程中贪心地记录当前匹配的主串位置,然后每当出现一个新匹配根据记录的位置判断这个新匹配是否成立,最后更新位置。
另外,考虑到数据可以出现多个模式串相同的情况,实现要做一些处理:
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 }