zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    es6语法快速上手(转载)
    width百分比
    利用switch case 来运行咱们结婚吧
    利用if else来运行咱们结婚吧
    利用if else 来计算车费
    利用switch case判断是今天的第多少天
    利用if else判断是否及格
    利用if,else判断输入的是不是一个正整数
    再练一遍猜拳
    用if else 判断是不是7的倍数等
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/10321906.html
Copyright © 2011-2022 走看看