【AC自动机】zoj3228 Searching the String

对所有模式串建立AC自动机。

每个单词结点要记录该单词长度。

然后在跑匹配的时候,对每个单词结点再处理3个值,代表可重叠的匹配次数,不可重叠的匹配次数,以及“上一次不可重叠的匹配位置”,这样结合单词长度就能保证不重叠。有多个重叠时,取靠前的位置更优。

Update:加了个优化,仅当某个结点的字符串的后缀可能是单词的时候,才会顺着fail指针往回跳。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
queue<int>q;
bool word[601000];
int child[601000][26],fail[601000],size,pos[101000];
int cnta[601000],cntb[601000],posn[601000],lens[601000];
void Insert(char S[],int id)
{
    int len=strlen(S);
    int now=0;
    for(int i=0;i<len;++i)
      {
        if(!child[now][S[i]-'a'])
          child[now][S[i]-'a']=size++;
        now=child[now][S[i]-'a'];
      }
    word[now]=1;
    lens[now]=len;
    pos[id]=now;
}
void build()
{
    fail[0]=-1;
    q.push(0);
    while(!q.empty())
      {
        int U=q.front(); q.pop();
        for(int i=0;i<26;++i)
          if(child[U][i])
            {
              int V=fail[U];
              while(V!=-1)
                {
                  if(child[V][i])
                    {
                      fail[child[U][i]]=child[V][i];
                      break;
                    }
                  V=fail[V];
                }
              if(V==-1)
                fail[child[U][i]]=0;
              if(word[fail[child[U][i]]])
                word[child[U][i]]=1;
              q.push(child[U][i]);
            }
      }
}
void match(char S[])
{
    int len=strlen(S);
    int res=0,now=0;
    for(int i=0;i<len;++i)
      {
        if(child[now][S[i]-'a'])
          now=child[now][S[i]-'a'];
        else
          {
            int U=fail[now];
            while(U!=-1 && child[U][S[i]-'a']==0)
              U=fail[U];
            if(U==-1)
              now=0;
            else
              now=child[U][S[i]-'a'];
          }
        if(!word[now])
          continue;
        int U=now;
        while(U)
          {
            if(word[U])
              {
                ++cnta[U];
                if(posn[U]<=i-lens[U])
                  {
                    ++cntb[U];
                    posn[U]=i;
                  }
              }
            U=fail[U];
          }
      }
}
void Init()
{
    memset(child,0,sizeof(child));
    memset(fail,0,sizeof(fail));
    memset(word,0,sizeof(word));
    memset(pos,0,sizeof(pos));
    memset(cnta,0,sizeof(cnta));
    memset(cntb,0,sizeof(cntb));
    memset(posn,-1,sizeof(posn));
    memset(lens,0,sizeof(lens));
    size=1;
}
char s[101000];
bool op[101000];
int n;
int main()
{
    char ss[9];
    int T=0;
    //freopen("zoj3228.in","r",stdin);
    while(scanf("%s%d",s,&n)!=EOF)
      {
        printf("Case %d
",++T);
        Init();
        for(int i=1;i<=n;++i)
          {
            scanf("%d%s",&op[i],ss);
            Insert(ss,i);
          }
        build();
        match(s);
        for(int i=1;i<=n;++i)
          printf("%d
",op[i] ? cntb[pos[i]] : cnta[pos[i]]);
        puts("");
      }
    return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/6506324.html