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 \n",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\n",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\n",i,t[i].fa,t[i].len);
    		for(int j=0;j<26;j++)
    			if(t[i].ch[j])	printf("*%d %d\n",j,t[i].ch[j]);
		}
	}
}sam;
int f[mxn*4]; bool vis[mxn*4];
char ch[mxn];
int search(int pos)
{
	//printf("%d %d\n",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\n");
        else    printf("%d\n",ans);
    }
    return 0;
}BZOJ5261 Rhyme的更多相关文章
- BZOJ2938 [Poi2000]病毒 和 BZOJ5261 Rhyme
		[Poi2000]病毒 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码 ... 
- Codeforces 792B. Counting-out Rhyme
		B. Counting-out Rhyme time limit per test: 1 second memory limit per test: 256 megabytes input: stan ... 
- [省选模拟]Rhyme
		考的时候脑子各种短路,用个SAM瞎搞了半天没搞出来,最后中午火急火燎的打了个SPFA才混了点分. 其实这个可以把每个模式串长度为$K-1$的字符串看作一个状态,这个用字符串Hash实现,然后我们发现这 ... 
- B. Counting-out Rhyme(约瑟夫环)
		Description n children are standing in a circle and playing the counting-out game. Children are numb ... 
- POJ1671 Rhyme Schemes
		Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 1776 Accepted: 984 Special Judge De ... 
- 2019上海网络赛 F. Rhyme scheme 普通dp
		Rhyme scheme Problem Describe A rhyme scheme is the pattern of rhymes at the end of each line of a p ... 
- CodeForce-792B Counting-out Rhyme(模拟)
		Counting-out Rhyme CodeForces - 792B 题意: n 个孩子在玩一个游戏. 孩子们站成一圈,按照顺时针顺序分别被标号为 1 到 n.开始游戏时,第一个孩子成为领导. 游 ... 
- BZOJ5261 Rhyme--广义SAM+拓扑排序
		原题链接,不是权限题 题目大意 有\(n\)个模板串,让你构造一个尽量长的串,使得这个串中任意一个长度为\(k\)的子串都是至少一个模板串的子串 题解 可以先看一下这道题 [POI2000]病毒 虽然 ... 
- BZOJ 5261 Rhyme
		思路 考虑一个匹配的过程,当一个节点x向后拼接一个c的时候,为了满足题目条件的限制,应该向suflink中最深的len[x]+1>=k的节点转移(保证该后缀拼上一个c之后,长度为k的子串依然属于 ... 
随机推荐
- HTML基础入门学习准备篇
			在学习前端的开始,让我们一起来了解什么是HTML5时代的大前端开发和全栈开发的定义 传统的前端:切图-标签和样式-实现效果 H5时代的前端: 一.需要各端的兼容开发 二.可以用于APP开发和移动站点的 ... 
- 数据库的目录IDF打不开!附加失败
			选择附加数据库,结果 武汉地图打不开 这是mapgis k9里面自带的地图 IDF:Identity Definition File?https://zhidao.baidu.com/question ... 
- C# 图片剪切与缩小的实例
			public void CutToF(Stream stream) { Image initImage = Image.FromStream(stream, true); && ini ... 
- Java学习、面试、求职、干货资源精品合集
			本系列文章整合了本号发表和转载过的,有关Java学习.进阶.面试.做项目.求职经验等方面的文章,希望对想要找工作,以及正在找工作的你,能够有所帮助. 原创Java学习专题文章: 如何才能够系统地学习J ... 
- 阿里云code上传代码
			1-从官网下载git,然后安装,这一步可以百度. 2-在阿里云上面创建project,如图 3-回到本地,进入本地代码文件目录,右击打开git 4-输入git init 在文件夹下面会出现.git文件 ... 
- CDN:BootCDN 项目列表-摘录-20180405
			ylbtech-CDN:BootCDN 项目列表-20180405 1.返回顶部 1. 2. 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 1. http://www.boo ... 
- 126、TensorFlow Session的执行
			# tf.Session.run 方法是一个执行tf.Operation或者计算tf.Tensor的一个主要的机制 # 你可以传递一个或者多个tf.Operation或者tf.Tensor对象来给tf ... 
- This service allows sftp connections only
			这是因为该用用户只开通了sftp,ssh被禁了 可以通过别的主机ssh登陆这台机器 app@home:/software>ssh mysftp@192.168.0.1 Authorized on ... 
- Caffe深入分析(源码)
			Caffe的整体流程图: 程序入口:main() int main(int argc, char** argv) { ..... ]))(); .... } g_brew_map实现过程,首先通过 t ... 
- Unity shader with lightmap
			小记一下用法与问题,时更 surface shader就不用操心了,自带lightmap计算 主要是vertex fragment shader部分 Unity5 bake light map有三种情 ... 
