CodeForces 427D Match & Catch

来源:互联网 发布:stc单片机是中国的吗 编辑:程序博客网 时间:2024/05/16 14:53

CodeForces 427D Match & Catch

SAM

题意

给两个串,求一个最小子串的长度,使得它是两个串的公共子串,且在两个子串中均只出现一次。

思路

对第一个串建自动机,求公共子串就是常规思路,不过跑的时候开个num数组记录,到一个点说明这个点代表的子串们出现了一次,记录这个次数,这是第二个串的次数。第一个串的次数在SAM中处理出来,那个endposamu数组。

至于每个状态,跑到了就说明这个状态的子串全部都出现过。所以最后取所有endposnum和num都为1的状态中minlen最小的值。

代码

别忘了无解输出-1

#include<bits/stdc++.h>#define M(a,b) memset(a,b,sizeof(a))typedef long long LL;using namespace std;const int MAXL=10005;const int MAXS=26;struct SAM{    int n=0, len, st;    int maxlen[2*MAXL+10], minlen[2*MAXL+10], trans[2*MAXL+10][MAXS], slink[2*MAXL+10], col[2*MAXL+10], indeg[2*MAXL+10], endposamu[2*MAXL+10], num[2*MAXL+10];    int new_state(int _maxlen, int _minlen, int* _trans, int _slink)    {        n++;        maxlen[n]=_maxlen;        minlen[n]=_minlen;        for(int i=0; i<MAXS; i++)        {            if(_trans==NULL)                trans[n][i]=0;            else                trans[n][i]=_trans[i];        }        slink[n]=_slink;        return n;    }    int add_char(char ch, int u)    {        int c=ch-'a';        int z=new_state(maxlen[u]+1, -1, NULL, 0);        col[z]=1;        int v=u;        while(v!=0&&trans[v][c]==0)        {            trans[v][c]=z;            v=slink[v];        }        if(v==0)        {            minlen[z]=1;            slink[z]=1;            indeg[1]++;            return z;        }        int x=trans[v][c];        if(maxlen[v]+1==maxlen[x])        {            minlen[z]=maxlen[x]+1;            slink[z]=x;            indeg[x]++;            return z;        }        int y=new_state(maxlen[v]+1, -1, trans[x], slink[x]);        col[y]=0;        minlen[x]=maxlen[y]+1;        slink[x]=y;        minlen[z]=maxlen[y]+1;        slink[z]=y;        indeg[y]+=2;        int w=v;        while(w!=0&&trans[w][c]==x)        {            trans[w][c]=y;            w=slink[w];        }        minlen[y]=maxlen[slink[y]]+1;        return z;    }    void init()    {        memset(col, 0, sizeof(col));        memset(indeg, 0, sizeof(indeg));        memset(maxlen, 0, sizeof(maxlen));        memset(minlen, 0, sizeof(maxlen));        memset(trans, 0, sizeof(maxlen));        memset(slink, 0, sizeof(maxlen));        memset(endposamu, 0, sizeof(endposamu));        memset(num, 0, sizeof(num));        n=0;        st=new_state(0, -1, NULL, 0);    }    void getendpos()    {        queue<int> que;        for(int i=st;i<=n;i++)        {            if(indeg[i]==0) que.push(i);            if(col[i]==1) endposamu[i]++;        }        while(!que.empty())        {            int pos=que.front();que.pop();            endposamu[slink[pos]]+=endposamu[pos];            indeg[slink[pos]]--;            if(indeg[slink[pos]]==0) que.push(slink[pos]);        }    }    void addstring(char* s,int len)    {        int la=st;        for(int i=0;i<len;i++)        {            la=add_char(s[i], la);        }        getendpos();    }    int match(char* s, int m)    {        int now=this->st;        for(int i=0;i<m;i++)        {            int k=s[i]-'a';            if(trans[now][k])            {                now=trans[now][k];                num[now]++;            }            else            {                while(!trans[now][k]&&now)                {                    now=slink[now];                }                if(!now)                {                    now=this->st;                }                else                {                    now=trans[now][k];                    num[now]++;                }            }        }        int ans=0x3f3f3f3f;        for(int i=this->st;i<=this->n;i++)        {            if(num[i]==1&&endposamu[i]==1)            {                ans=min(ans, minlen[i]);            }        }        if(ans>=0x3f3f3f3f) return -1;        return ans;    }}sam;char ss[MAXL*2+7];int main(){    sam.init();    scanf("%s", ss);    int n=strlen(ss);    sam.addstring(ss, n);    scanf("%s", ss);    int m=strlen(ss);    cout<<sam.match(ss, m)<<endl;    //system("pause");    return 0;}
原创粉丝点击