BZOJ5261 Rhyme

传送门

广义后缀自动机= =+

跟ptx大爷的博客学的 戳我传送

我写的第一种 建立Trie树的写法 bfs建立SAM

为什么是bfs呢 我也不知道(GG) 经过我一番抱大腿+询问 各位大爷说的原因是 因为dfs时间复杂度不对

多有道理哦 【摔

不过好像这个复杂度保证好像真的不大准确2333

所以 安安心心bfs就最吼啦 复杂度貌似是trie的大小

其实 每次重置last为rt也可以啊qwq 这个复杂度是字符串总长度的

那么这个题的做法就是 建立完SAM 然后 我们类似AC自动机一样建立类fail指针一样的东西

这个指针要保证len>=k 并且两个可以连接起来 也就是x向parent上跳 并且x和上面的串长都要是>=k的 然后找到有这个字符的地方链接就好啦

那么最后我们要求的就是这个新图的最长路

如果出现环了当然就是INF了qwq

附代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 20021225
#define ll long long
#define mxn 100010
using namespace std;

struct node{int fa,len,ch[26],c;};
struct edge{int to,lt;}e[mxn*20];
int cnt,in[mxn*4],k;
void add(int x,int y)
{
    e[++cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;
}
struct trie
{
    node t[mxn];int rt,poi;
    void init()
    {
        for(int i=1;i<=poi;i++) memset(t[i].ch,0,sizeof(t[i].ch)),t[i].fa=t[i].c=0;
        rt=poi=1;
    }
    void insert(char *ch)
    {
        int n=strlen(ch),pos=rt;
        for(int i=0;i<n;i++)
        {
            int tmp=ch[i]-'a';
            if(!t[pos].ch[tmp])
                t[pos].ch[tmp]=++poi,t[poi].fa=pos,t[poi].c=tmp;
            pos=t[pos].ch[tmp];
        }
    }
}tr;
struct SAM
{
    node t[mxn*4]; int poi,rt,lt[mxn*4];
    queue<int> que;
    void init()
    {
        memset(lt,0,sizeof(lt));
        for(int i=1;i<=poi;i++) memset(t[i].ch,0,sizeof(t[i].ch)),t[i].fa=t[i].c=t[i].len=0;
        poi=0;rt=++poi;
    }
    int insert(int c,int lt)
    {
        int p=lt,np=++poi; t[np].len=t[lt].len+1;
        for(;p&&!t[p].ch[c];p=t[p].fa)  t[p].ch[c]=np;
        if(!p){t[np].fa=rt;return np;}
        int q=t[p].ch[c];
        if(t[q].len==t[p].len+1){t[np].fa=q;return np;}
        int nq=++poi; t[nq].len=t[p].len+1;
        memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch));
        t[nq].fa=t[q].fa; t[np].fa=t[q].fa=nq;
        for(;p&&t[p].ch[c]==q;p=t[p].fa) t[p].ch[c]=nq;
        return np;
    }
    void build()
    {
        init();
        while(!que.empty()) que.pop();
        for(int i=0;i<26;i++)
            if(tr.t[rt].ch[i])  que.push(tr.t[rt].ch[i]);
        lt[tr.rt]=rt;
        while(!que.empty())
        {
            int pos=que.front(); que.pop();
            //printf("%d 
",pos);
            lt[pos]=insert(tr.t[pos].c,lt[tr.t[pos].fa]);
            for(int i=0;i<26;i++)
                if(tr.t[pos].ch[i]) que.push(tr.t[pos].ch[i]);
        }
    }
    void makemap()
    {
        for(int i=1;i<=poi;i++)
            if(t[i].len>=k)
            {
                for(int c=0;c<26;c++)
                {
                    if(t[i].ch[c])
                    {
                        if(t[t[i].ch[c]].len>=k)    add(t[i].ch[c],i);
                    }
                    else
                    {
                        int p=i;
                        while(p&&!t[p].ch[c]&&t[p].len>=k)  p=t[p].fa;
                        int np=t[p].ch[c];// printf("%d %d %d %d
",i,p,np,t[np].len);
                        if(p&&np&&t[p].len+1>=k) t[i].ch[c]=np,add(np,i);
                    }
                }
            }
    }
    void print()
    {
    	for(int i=1;i<=poi;i++)
    	{
    		printf("id=%d:%d %d
",i,t[i].fa,t[i].len);
    		for(int j=0;j<26;j++)
    			if(t[i].ch[j])	printf("*%d %d
",j,t[i].ch[j]);
		}
	}
}sam;
int f[mxn*4]; bool vis[mxn*4];
char ch[mxn];
int search(int pos)
{
	//printf("%d %d
",pos,f[pos]);
    if(vis[pos])    return f[pos]=inf;
    if(~f[pos]) return f[pos];
    f[pos]=sam.t[pos].len;	vis[pos]=1;
    for(int i=in[pos];i;i=e[i].lt)
    {
        int y=e[i].to; int tmp=search(y);
        if(tmp==inf)    return f[pos]=inf;
        f[pos] = max(f[pos],tmp+1);
    }
    vis[pos]=0; return f[pos];
}
void init()
{
	for(int i=1;i<=cnt;i++)
		e[i].to=e[i].lt=0;
	cnt=0;memset(in,0,sizeof(in));
    memset(f,-1,sizeof(f));
    memset(vis,0,sizeof(vis));
}
int main()
{
    int t;
    while(~scanf("%d%d",&t,&k))
    {
    	init();
        tr.init();//tr.rt=tr.poi=1;
        while(t--)
        {
            scanf("%s",ch);
            tr.insert(ch);
        }
        sam.build();
        sam.makemap();
        //sam.print();
        int ans=k-1;
        for(int i=1;i<=sam.poi;i++)
            if(sam.t[i].len>=k&&f[i]==-1)
                search(i);
        for(int i=1;i<=sam.poi;i++)	ans=max(ans,f[i]);
        if(ans>=inf)    printf("INF
");
        else    printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hanyuweining/p/10321906.html