hdu6138 Fleet of the Eternal Throne AC自动机

来源:互联网 发布:数据网络开关在那 编辑:程序博客网 时间:2024/06/08 13:14

题目:给你n个字符串,m个询问,问x,y这两个字符串的最长子串,并且这个子串也是某个字符串的前缀。

思路:AC自动机,n个串插入自动机中,在用x串跑一遍自动机,把经过的点标记下来,再用y串跑一遍,看这个点是否走过,走过的话,就有可能成为答案。

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<vector>#include<map>#include<set>#include<queue>#include<stack>#include<list>#include<numeric>using namespace std;#define LL long long#define ULL unsigned long long#define INF 0x3f3f3f3f#define mm(a,b) memset(a,b,sizeof(a))#define PP puts("*********************");template<class T> T f_abs(T a){ return a > 0 ? a : -a; }template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}// 0x3f3f3f3f3f3f3f3f// 0x3f3f3f3fconst int SIGMA_SIZE = 26;const int MAXNODE = 2e5+50;const int maxn=2e5+50;int ch[MAXNODE][SIGMA_SIZE];int f[MAXNODE];// fail函数int dep[MAXNODE];int vis[MAXNODE];int sz;void AC_init(){    sz=1;    mm(ch[0],0);    mm(vis,0);    dep[0]=0;}// 字符c的编号int idx(char c){    return c-'a';}// 插入字符串。v必须非0void AC_insert(char *s){    int u=0,n=strlen(s);    for(int i=0;i<n;i++){        int c=idx(s[i]);        if(!ch[u][c]){            mm(ch[sz],0);            vis[sz]=0;            dep[sz]=dep[u]+1;            ch[u][c]=sz++;        }        u=ch[u][c];    }}// 计算fail函数void AC_getFail(){    queue<int>q;    f[0]=0;    // 初始化队列    for(int c=0;c<SIGMA_SIZE;c++){        int u=ch[0][c];        if(u){            f[u]=0;q.push(u);        }    }    // 按BFS顺序计算fail    while(!q.empty()){        int r=q.front();q.pop();        for(int c=0;c<SIGMA_SIZE;c++){            int u=ch[r][c];            //if(!u) continue;            if(!u){//将不存在的边不上,这是为了将所有的转移一视同仁                ch[r][c]=ch[f[r]][c];continue;            }            q.push(u);            int v=f[r];            while(v&&!ch[v][c]) v=f[v];            f[u]=ch[v][c];        }    }}int AC_find(char *T,int now){    int n=strlen(T);    int j=0;// 当前结点编号,初始为根结点    for(int i=0;i<n;i++){// 文本串当前指针        int c=idx(T[i]);        //while(j&&!ch[j][c]) j=f[j];// 顺着失配边走,直到可以匹配        j=ch[j][c];        int tmp=j;        while(tmp){            vis[tmp]=now;//            printf("%d  ",tmp);            tmp=f[tmp];        }    }//    printf("\n");}int AC_Query(char *T,int now){    int n=strlen(T);    int j=0;// 当前结点编号,初始为根结点    int ans=0;    for(int i=0;i<n;i++){// 文本串当前指针        int c=idx(T[i]);        //while(j&&!ch[j][c]) j=f[j];// 顺着失配边走,直到可以匹配        j=ch[j][c];        int tmp=j;        while(tmp){            if(vis[tmp]==now){                ans=max(ans,dep[tmp]);            }//            printf("%d  ",tmp);            tmp=f[tmp];        }    }//    printf("\n");    return ans;}char s[maxn];int pos[maxn];int main(){    int T,n,m,x,y;    scanf("%d",&T);    while(T--){        AC_init();        int d=0;        scanf("%d",&n);        for(int i=0;i<n;i++){            pos[i]=d;            scanf("%s",s+d);            AC_insert(s+d);            d+=strlen(s+d)+1;        }        AC_getFail();        scanf("%d",&m);        int now=0;        while(m--){            scanf("%d%d",&x,&y);x--;y--;            now++;            AC_find(s+pos[x],now);            int ans=AC_Query(s+pos[y],now);            printf("%d\n",ans);        }    }    return 0;}


原创粉丝点击