P1368 后缀自动机(SAM)+ map 求循环序列中最小长度为k的子串

题意:给出一串序列,序列可循环,请你求出长度为n的最小子串

输入 #1
10
10 9 8 7 6 5 4 3 2 1
输出 #1
1 10 9

这道题显然可以用最小表示法做,但也是一道不错的后缀自动机入门题。下面给出两个算法的处理速度。
最小表示法:
最小表示法
后缀自动机:
后缀自动机
可以看到最小表示法速度上很优秀,但是后缀自动机也能过得很稳。这里不再介绍最小表示法~~(因为比较简单)~~

下面的做法需要有后缀自动机的基础,需要入门的可以看看这个dalao的博客:https://www.cnblogs.com/zjp-shadow/p/9218214.html

下面我们分析一下后缀自动机的做法,其实就是建出来就行
由于后缀自动机的特性我们可以得知,
1,从一个点开始按着边走必然能走过一个字串
2,每个状态存储的转移数组(像trie一样的数组)所存储的内容,就是下一跳的状态
3,map有内部有序且能存下pair的特性
至此,我们当然会选择map数组来代替普通转移数组,map.first存储边,map.second存储经过这条边到达的状态。
所以我们建好自动机之后就可以顺着每个状态的最小边直接取n个数输出就好了。
还有一点,喜欢用结构体的好像存不下吗,这里换用数组模拟。

//
// Created by SANZONG on 2020/11/30.
//

#include "bits/stdc++.h"
#define mem(x,i) memset(x,i,sizeof(x))
using namespace std;
const int MAXN = 3e5+10;

int len[MAXN<<2];
map<int,int> ch[MAXN<<2];
int fa[MAXN<<2];
int last = 1;
int tot = 1;

void add(int c)
{
    int p = last;
    last = ++tot;
    int np = last;
    len[np] = len[p]+1;
    for (; p&&!ch[p][c] ; p = fa[p]) ch[p][c] = np;
    if (!p) fa[np] = 1;
    else
    {
        int q = ch[p][c];
        if (len[q] == len[p]+1) fa[np] = q;
        else
        {
            int nq = ++tot;
            fa[nq] = fa[q];
            ch[nq] = ch[q];
            len[nq] = len[p]+1;
            fa[np] = fa[q] =  nq;
            for (;p&& ch[p][c] == q ; p = fa[p]) {
                ch[p][c] = nq;
            }
        }
    }
}
int s[MAXN<<1];
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int n;
    scanf("%d",&n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d",&s[i]);
        s[i+n] = s[i];
    }
    for (int i = 1; i <= (n<<1); ++i) {
        add(s[i]);
    }
    int p = 1;
    for (int i = 1; i <= n; ++i) {
        map<int,int>::iterator q = ch[p].begin();
        printf("%d ",q->first);
        p = q->second;
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值