bzoj千题计划284:bzoj2882: 工艺

http://www.lydsy.com/JudgeOnline/problem.php?id=2882

将串S复制一遍变成SS

对SS构建后缀自动机,在上面走标号最小的边len(S)步,即可得最小循环串

因为后缀自动机可以识别串的所有后缀

而S的最小循环串一定是SS后缀的前缀

#include<map>
#include<cstdio>
#include<iostream>

using namespace std;

#define N 600001

int a[N];

map<int,int>ch[N<<1];
int tot=1,fa[N<<1],len[N<<1];
int last=1,p,q,np,nq;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void extend(int c)
{
    len[np=++tot]=len[last]+1;
    for(p=last;p && ch[p].find(c)==ch[p].end();p=fa[p]) ch[p][c]=np;
    if(!p) fa[np]=1;
    else
    {
        q=ch[p][c];
        if(len[q]==len[p]+1) fa[np]=q;
        else
        {
            len[nq=++tot]=len[p]+1;
            ch[nq]=ch[q]; fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
        }
    }
    last=np;
}

int main()
{
    int n,x;
    read(n);
    for(int i=1;i<=n;++i)
    {
        read(x);
        extend(x);
        a[i]=x;
    }
    for(int i=1;i<=n;++i) extend(a[i]);
    map<int,int>::iterator it;
    int now=1;
    for(int i=1;i<=n;++i)
    {
        if(i>1) putchar(' ');
        it=ch[now].begin();
        printf("%d",it->first);
        now=ch[now][it->first];
    }
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8575482.html