UVALive 7902 后缀自动机

来源:互联网 发布:蚂蚁信息源码 编辑:程序博客网 时间:2024/06/08 14:50

题意

给N个字符串,找出第一个字符串中最短的一个子串,使得这个子串不在其他所有的字符串中出现。

题解

对于这样一道题,没有现成的工具可以利用,但是既然涉及到了子串的问题,就可以考虑后缀自动机。后缀自动机可以用来找最长公共子串。对于这道题,我们想要利用后缀自动机,就是需要采取一些措施,使得这个问题转化为最长公共子串的问题。
我们可以把其他字符串拼接成一个字符串,需要注意的是要在中间加上一个分割字符,因为如果没有这个字符的话,那么很有可能这个字符串与下一个字符串拼接成一个新的字符串,从而对结果产生影响。
拼接成一个字符串以后,把这个字符串加到后缀自动机上,就可以寻找最长公共子串了,在寻找最长公共子串的过程中,如果发生了失配,那么就意味着存在一段子串,这段子串不在任何一个字符串中存在,而这个字符串的长度就是当前匹配的最长公共子串长度-1。(这个原因是显而易见的,因为匹配失败就意味着不存在这个字串在其他字符串中。)这时候我们就需要比较一下字典序,进行答案的记录。
最后输出记录的位置对应的字符串就可以了。

代码

#include<bits/stdc++.h>#define UP(i,l,h) for(int i=l;i<h;i++)#define W(t) while(t)#define MEM(a,b) memset(a,b,sizeof(a))#define LL long long#define INF 0x3f3f3f3f#define eps 1e-10#define MAXN 3000010using namespace std;const int N=250010;char first[N];char second[N];struct Node {    int st,ed;    Node() {}    Node(int st,int ed):st(st),ed(ed) {}    bool operator < (const Node b) const {        int lena=(ed-st+1),lenb=(b.ed-b.st+1);        if(lena==lenb) {            UP(i,0,lena) {                if(first[st+i]!=first[b.st+i]) {                    return first[st+i]<first[b.st+i];                }            }            return true;        }        return lena<lenb;    }};Node ans;struct Suffix_Auto {    static const int NODE=N<<1,C=27;    int allc,last,par[NODE],len[NODE],trans[NODE][C];    int newNode() {        int ret=++allc;        MEM(trans[ret],0);        return  ret;    }    void init() {        allc=0;        last=newNode();        par[last]=len[last]=0;    }    void extend(int c) {        int p=last,np=newNode();        len[np]=len[last]+1;        for(; p&&!trans[p][c]; p=par[p]) trans[p][c]=np;        if(!p) par[np]=1;        else {            int q=trans[p][c];            if(len[q]==len[p]+1) par[np]=q;            else {                int nq=++allc;                par[nq]=par[q];                len[nq]=len[p]+1;                memcpy(trans[nq],trans[q],C<<2);                par[np]=par[q]=nq;                for(trans[p][c]=nq,p=par[p]; p&&trans[p][c]==q; p=par[p]) trans[p][c]=nq;            }        }        last=np;    }    void update(Node nd) {        if(ans.st==-1) {            ans=nd;        } else if(nd<ans) {            ans=nd;        }    }    void find(const char *st) {        int stlen=strlen(st);        int u=1;        int now=0;        UP(i,0,stlen) {            int x=st[i]-'a';            if(trans[u][x]) {                u=trans[u][x];                now++;            } else {                W(u&&!trans[u][x]) {                    u=par[u];                    now=len[u];                }                if(u) {                    now++;                    u=trans[u][x];                } else {                    now=0;                    u=1;                }                Node newNd=Node(i-now,i);                update(newNd);            }        }    }};Suffix_Auto sa;int main() {//    freopen("d://in.txt","r",stdin);//    freopen("d://out1.txt","w",stdout);    int ks=1;    int t;    scanf("%d",&t);    W(t--) {        sa.init();        int n;        scanf("%d",&n);        UP(i,0,n) {            if(i==0)                scanf("%s",first);            else {                scanf("%s",second);                int len=strlen(second);                UP(i,0,len) sa.extend(second[i]-'a');                sa.extend(26);            }        }        ans.st=-1;        sa.find(first);        printf("Case #%d: ",ks++);        if(ans.st==-1) {            printf("Impossible\n");        } else {            UP(i,ans.st,ans.ed+1) printf("%c",first[i]);            puts("");        }    }}
原创粉丝点击