热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

BZOJ1396:识别子串(后缀自动机+单调队列)

题面题意:给出一个串串,对于每个位置求包含每个位置的,最短的,只出现一次的子串的长度由区间的套路,只要求出以每个位置为L,最小的R,设为f[L]rolepresentati

题面
题意:给出一个串串,对于每个位置
求包含每个位置的,最短的,只出现一次的子串的长度

由区间的套路,只要求出以每个位置为L,最小的R,设为f[L]" role="presentation" > f [ L ]

显然f" role="presentation" > f 单调不降

在后缀自动机上,考虑Right集大小为1的状态T
发现f[1]到f[dep[T]−Min(T)+1]" role="presentation" > f [ 1 ] f [ d e p [ T ] M i n ( T ) + 1 ] 可用dep[T]更新

对于每个位置i,考虑以它为右端点
找到第一个f[h]<i" role="presentation" > f [ h ] < i 的h,i-h+1可更新ans[i]
若不以其为右端点,则j&#x2208;[h+1,i]" role="presentation" > j [ h + 1 , i ] f[j]&#x2212;j+1" role="presentation" > f [ j ] j + 1 可更新ans[i]

单调队列维护即可
zenzen不用线段树哦

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=400200,oo=1e9+7;

int n;
int pre[N],dep[N],r[N],son[N][26],cnt=1,last=1;
int head[N],nex[N],to[N],cur;
int len[N],ans[N],q[N];
char s[N];

void add(int u,int v)
{
    to[++cur]=v;
    nex[cur]=head[u];
    head[u]=cur;
}

void dfs(int x)
{
    for(int h=head[x];h;h=nex[h])
    dfs(to[h]),r[x]+=r[to[h]];
}

void Insert(int x)
{
    dep[++cnt]=dep[last]+1;
    int np=cnt,p=last;
    last=cnt;
    r[np]=1;
    for(;!son[p][x];p=pre[p])
    son[p][x]=np;
    if(!p)
    pre[np]=1;
    else
    {
        int q=son[p][x];
        if(dep[q]==dep[p]+1)
        pre[np]=q;
        else
        {
            dep[++cnt]=dep[p]+1;
            int nq=cnt;
            pre[nq]=pre[q];
            pre[q]=pre[np]=nq;
            mmcp(son[nq],son[q]);
            for(;son[p][x]==q;p=pre[p])
            son[p][x]=nq;
        }
    }
}

int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++)
    Insert(s[i]-'a');

    for(int i=2;i<=cnt;i++)
    add(pre[i],i);

    dfs(1);
    for(int i=1;i<=n;i++)
    ans[i]=len[i]=oo;

    for(int i=2;i<=cnt;i++)
    if(r[i]==1)
    len[dep[i]-dep[pre[i]]]=min(len[dep[i]-dep[pre[i]]],dep[i]);

    for(int i=n-1;i>=1;i--)
    len[i]=min(len[i],len[i+1]);

    int now=n,hh=1,tt=0;
    for(int i=n;i>=1;i--)
    {
        while(now>=1&&len[now]>i)
        {
            while(hh<=tt&&len[q[tt]]-q[tt]>=len[now]-now)
            tt--;
            if(len[now]!=oo&&now<=i)
            q[++tt]=now;
            now--;
        }
        if(now)
        ans[i]=min(ans[i],i-now+1);
        if(hh<=tt)
        ans[i]=min(ans[i],len[q[hh]]-q[hh]+1);
        if(q[hh]==i)
        hh++;
    }

    for(int i=1;i<=n;i++)
    printf("%d\n",ans[i]);

    return 0;
}

推荐阅读
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了栈和队列的区别及其特点。栈是一种先进后出的线性表,只能在表的一端进行插入和删除操作;队列是一种先进先出的线性表,只能在表的一端进行插入和在另一端进行删除操作。栈和队列是两种广泛使用的线性数据结构,它们的基本操作具有特殊性。栈的遍历需要遍历整个栈才能取出数据,并需要为数据开辟临时空间,而队列基于地址指针进行遍历,可以从头或尾部开始遍历,但不能同时遍历,且无需开辟临时空间。栈和队列在程序设计中具有重要应用。 ... [详细]
  • Linux的uucico命令使用方法及工作模式介绍
    本文介绍了Linux的uucico命令的使用方法和工作模式,包括主动模式和附属模式。uucico是用来处理uucp或uux送到队列的文件传输工具,具有操作简单快捷、实用性强的特点。文章还介绍了uucico命令的参数及其说明,包括-c或--quiet、-C或--ifwork、-D或--nodetach、-e或--loop、-f或--force、-i或--stdin、-I--config、-l或--prompt等。通过本文的学习,读者可以更好地掌握Linux的uucico命令的使用方法。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 一、什么是闭包?有什么作用什么是闭包闭包是定义在一个函数内部的函数,它可以访问父级函数的内部变量。当一个闭包被创建时,会关联一个作用域—— ... [详细]
  • 本文讨论了读书的目的以及学习算法的重要性,并介绍了两个算法:除法速算和约瑟夫环的数学算法。同时,通过具体的例子和推理,解释了为什么x=x+k序列中的第一个人的位置为k,以及序列2和序列3的关系。通过学习算法,可以提高思维能力和解决问题的能力。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
author-avatar
g我爱他偶买噶
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有