SPOJ lcs2 Longest Common Substring II 后缀自动机

来源:互联网 发布:斯洛文尼亚 旅行 知乎 编辑:程序博客网 时间:2024/05/22 17:23

题意:求n个串的最长公共子串(连续的)

方法:用其中一串构建后缀自动机,其它串来跑,并更新其len(step)即答案。

PS:本来是另一开一个数组来记录时间的,但状态转移时要用到SAM_node的标号,增加了时间复杂度常数,被卡了时间

#include <stdio.h>#include <stdlib.h>#include <vector>#include <algorithm>#include <iostream>#include <math.h>#include <string.h>using namespace std;typedef long long ll;const int Mod=1e9+7;const int N=1e5+5;int n;struct SAM_Node{    SAM_Node *fa,*next[26];    int len;    int pos,temp;    SAM_Node(){}    SAM_Node(int _len){        fa=0;len=_len;temp=0;        memset(next,0,sizeof(next));    }};SAM_Node SAM_node[N<<1],*SAM_root,*SAM_last,*b[N<<1];int SAM_size;SAM_Node *newSAM_Node(int len){    SAM_node[SAM_size]=SAM_Node(len);    SAM_node[SAM_size].pos=SAM_size;    return &SAM_node[SAM_size++];}SAM_Node *newSAM_Node(SAM_Node *p){    SAM_node[SAM_size]=*p;    SAM_node[SAM_size].pos=SAM_size;    return &SAM_node[SAM_size++];}void SAM_init(){    SAM_size=0;    SAM_root=SAM_last=newSAM_Node(0);    SAM_node[0].pos=0;}void SAM_add(int x,int len){    SAM_Node *p=SAM_last,*np=newSAM_Node(p->len+1);    SAM_last=np;    for(;p&&!p->next[x];p=p->fa)p->next[x]=np;    if(!p){        np->fa=SAM_root;        return;    }    SAM_Node *q=p->next[x];    if(q->len==p->len+1){        np->fa=q;        return;    }    //puts("3");    SAM_Node *nq=newSAM_Node(q);    nq->len=p->len+1;    q->fa=nq;    np->fa=nq;    for(;p&&p->next[x]==q;p=p->fa)p->next[x]=nq;}char a[N];int dp[N<<1];int rank[N<<1],cnt[N<<1];void Sort(){    memset(cnt,0,sizeof(cnt));    for(int i=0;i<SAM_size;i++)        cnt[SAM_node[i].len]++;    for(int i=1;i<=n;i++)        cnt[i]+=cnt[i-1];    for(int i=0;i<SAM_size;i++){        //rank[--cnt[SAM_node[i].len]]=i;        b[--cnt[SAM_node[i].len]]=&SAM_node[i];    }}void work(){    int T;    SAM_init();    scanf("%s",a+1);    n=strlen(a+1);    for(int i=1;i<=n;i++)        SAM_add(a[i]-'a',i);    Sort();    int ret=0;//    for(int i=0;i<SAM_size;i++)//        cnt[i]=SAM_node[i].len;    while(~scanf("%s",a+1)){        n=strlen(a+1);        SAM_Node *Cur=SAM_root;        int temp=0;        for(int i=1;i<=n;i++){            int u=a[i]-'a';            if(Cur->next[u]){                temp++;                Cur=Cur->next[u];            }            else{                while(true){                    Cur=Cur->fa;                    if(!Cur)break;                    if(Cur->next[u])break;                }                if(!Cur){                    Cur=SAM_root;temp=0;                }                else{                    temp=Cur->len+1;                    Cur=Cur->next[u];                }            }            //u=Cur->pos;            //dp[u]=max(dp[u],temp);Cur->temp=max(Cur->temp,temp);        }        int u,v;        for(int i=SAM_size-1;i>0;i--){            //u=rank[i];            //v=SAM_node[u].fa->pos;            //dp[v]=max(dp[v],dp[u]);            //cnt[u]=min(cnt[u],dp[u]);            //dp[u]=0;            //u=b[i]->pos;v=b[i]->fa->pos;            //dp[v]=max(dp[v],dp[u]);            //b[i]->len=min(b[i]->len,dp[u]);            //dp[u]=0;b[i]->fa->temp=max(b[i]->fa->temp,b[i]->temp);b[i]->len=min(b[i]->len,b[i]->temp);b[i]->temp=0;        }    }    for(int i=1;i<SAM_size;i++)        ret=max(ret,b[i]->len);    printf("%d\n",ret);}int main(){    freopen("data_in.txt","r",stdin);    //freopen("C_out.txt","w",stdout);    work();    return 0;}


0 0
原创粉丝点击