求助AC自动机
查看原帖
求助AC自动机
358779
Waaifu_D楼主2022/7/27 20:59

Rt,思路是建完AC之后用主串标记能遍历到的AC上的点,然后用模式串再找一遍最长的长度

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
string T;
int n,m;
struct node
{
    int vis[5];
    int fail;
    int end;
}c[10000005];
//int match[1000005];
int cnt;
string ask[100005];
inline int getsum(char a)
{
    if(a=='E') return 1;
    if(a=='S') return 2;
    if(a=='W') return 3;
    if(a=='N') return 4;
}
inline void insert(string s,int num)
{
    int len=s.size();
    int pos=0;
    for(register int i=0; i<len;i++)
    {
        int k=getsum(s[i]);
        if(!c[pos].vis[k])
        {
            c[pos].vis[k]=++cnt;
        }
    }
  //  match[num]=pos;
}
inline void build()
{
    queue<int> q;
    for(register int i=1; i<=4;i++)
    {
        if(c[0].vis[i])
        {
            c[c[0].vis[i]].fail=0;
            q.push(c[0].vis[i]);
        }
    }
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(register int i=1; i<=4;i++)
        {
            if(c[now].vis[i])
            {
                c[c[now].vis[i]].fail=c[c[now].fail].vis[i];
                q.push(c[now].vis[i]);
            }
            else c[now].vis[i]=c[c[now].fail].vis[i];
        }
    }
}
inline void query(string s)
{
    int pos=0;
    int len=s.size();
    for(register int i=0; i<len;i++)
    {
        int k=getsum(s[i]);
        pos=c[pos].vis[k];
        for(register int j=pos;j;j=c[j].fail)
        {
            if(c[j].end) break;
            c[j].end=1;
        }
    }
    for(register int i=1; i<=m;i++)
    {
        int res=0,p=0;
        for(register int j=0; j<ask[i].size();j++)
        {
            p=c[p].vis[getsum(ask[i][j])];
            if(c[p].end) res=j+1;
        }
        printf("%d\n",res);
    }
}
int main()
{
    cin>>n>>m>>T;
    for(register int i=1; i<=m;i++)
    {
        cin>>ask[i];
        insert(ask[i],i);
    }
    build();
    query(T);
    return 0;
}
2022/7/27 20:59
加载中...