UOJ Logo kczno1的博客

博客

fzu AC自动机

2017-08-06 16:37:33 By kczno1

没有题解我来发一个。(同时来存模板)

http://acm.fzu.edu.cn/problem.php?pid=2246

第1种情况,t直接出现在s中。

那么要么割前面要么割后面。

求出t在s中第一次出现的位置和最后一次出现的位置即可。

第2种情况,t分成两半出现在s中。

那么枚举被分成哪两半,求出前缀在s中第一次出现的位置和后缀在s中最后一次出现的位置即可。

要求m个串的所有前缀在s中第一次出现的位置,建ac自动机,让s跑一遍就好了。

后缀的话全反过来做一遍就好了。

要注意: ac自动机中fail[i]不一定<i, 但深度顺序或者bfs序一定<i。(因为是i的后缀)

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#include<iostream>
//#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define mid (l+r>>1)
#define pb push_back
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)

template <typename T> inline void chmin(T &x,const T &y)
{
    if(x>y)x=y;
}
template <typename T> inline void chmax(T &x,const T &y)
{
    if(x<y)x=y;
}

#define gc (c=getchar())
int read()
{
    char c;
    while(gc<'-');
    if(c=='-')
    {
        int x=gc-'0';
        while(gc>='0')x=x*10+c-'0';
        return -x;
    }
    int x=c-'0';
    while(gc>='0')x=x*10+c-'0';
    return x;
}

struct vec
{
    int *a,n;
    void pb(int x)
    {
        if((n&-n)==n)
        {
            int *_a=new int [n*2];
            memcpy(_a,a,n*sizeof(int));
            a=_a;
        }
        a[n++]=x;
    }
};
#define fore(arr) for(int *it=arr.a,*end=arr.a+arr.n;it!=end;++it)

const int N=1e5+500;
char s[N],T[N*2];int mn1[N*2],mn2[N],t[N],len[N];

int fail[N],ch[N][26],mn[N];int tot;
void ins(char *s)
{
    int i=1;
    for(char *c=s;*c>'0';++c)
    {
        int &to=ch[i][*c-'a'];
        i=to?to:(to=++tot);
    }
}
int q[N],tail;
void init_fail()
{
    tail=1;q[1]=1;
    for(int head=1;head<=tail;++head)
    {
        int i=q[head];
        int f=fail[i];
        rep(j,0,26-1)
        if(ch[i][j]) fail[q[++tail]=ch[i][j]]=ch[f][j];
        else ch[i][j]=ch[f][j];
    }
}
void travel(char *s)
{
    memset(mn+1,1<<5,tot*sizeof(int));
    int i=1,l=0;
    for(char *c=s;*c>'0';++c,++l) chmin(mn[i=ch[i][*c-'a']],l);
    for(int i=tot;i;--i) chmin(mn[fail[q[i]]],mn[q[i]]);
}
void Get(int *f,char *s)
{
    int i=1,l=0;
    for(char *c=s;*c>'0';++c,++l)
    {
        i=ch[i][*c-'a'];
        f[l]=mn[i];
    }
}

int main()
{
    freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    int tt=read();
    rep(j,0,25)ch[0][j]=1;
    while(tt--)
    {
        scanf("%s",s);
        int n=strlen(s);

        memset(ch+1,0,tot*sizeof(*ch));
        tot=1;

        int m;
        cin>>m;
        int nt=0;
        rep(i,1,m) 
        {
            scanf("%s",T+(t[i]=nt));
            len[i]=strlen(T+nt);
            ins(T+nt);
            nt+=len[i]+1;
        }
        init_fail();

        travel(s);
        rep(i,1,m) 
        {
            Get(mn1+t[i],T+t[i]);
        }

        reverse(s,s+n);
        rep(i,1,m) reverse(T+t[i],T+t[i]+len[i]);

        memset(ch+1,0,tot*sizeof(*ch));
        tot=1;

        rep(i,1,m) ins(T+t[i]);
        init_fail();

        travel(s);
        rep(i,1,m) 
        {    
           Get(mn2,T+t[i]);
           int l=len[i],*mn=mn1+t[i];
           int ans=max(n-1-mn[l-1],n-1-mn2[l-1]);
           rep(j,1,l-1) 
            chmax(ans, n-(mn[j-1]+1+mn2[l-1-j]+1) );
           if(ans<0) puts("-1");
           else printf("%d\n",ans);
        }
    }
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。