【工艺】

好像是最小表示法的板子题呢

但是不会啊,于是就变成了我的第一道\(SAM\)

对于这种跟循环同构有关系的题,显然需要将原来的串倍长,之后先插入到\(SAM\)里去

之后我们在\(SAM\)上找到贪心访问最小的儿子找到一条长度为\(n\)的路径就好了

显然因为我们循环同构了,所以从根到根的任何一个转移必然会存在一个长度为\(n\)的路径

字符集很大,需要开\(map\)

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#define re register
#define LL long long
#define maxn 600005
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
    re char c=getchar();int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
std::map<int,int> son[maxn<<1];
int a[maxn];
int link[maxn<<1],len[maxn<<1],sz[maxn<<1];
int lst=1,n,m,cnt=1,now=0;
inline void ins(int c)
{
    int f=lst,p=++cnt; lst=p;
    len[p]=len[f]+1,sz[p]=1;
    while(f&&!son[f][c]) son[f][c]=p,f=link[f];
    if(!f) {link[p]=1;return;}
    int x=son[f][c];
    if(len[f]+1==len[x]) {link[p]=x;return;}
    int y=++cnt;
    len[y]=len[f]+1,link[y]=link[x],link[x]=link[p]=y;
    for(std::map<int,int>::iterator i=son[x].begin();i!=son[x].end();++i) son[y].insert(*i);
    while(f&&son[f][c]==x) son[f][c]=y,f=link[f];
}
void dfs(int x)
{
    if(now==n) return;
    std::map<int,int>::iterator i=son[x].begin();
    int t=(*i).first;
    printf("%d ",t);now++;
    dfs((*i).second);
}
int main()
{
    n=read();
    for(re int i=1;i<=n;i++) a[i]=a[i+n]=read();
    for(re int i=1;i<=2*n;i++) ins(a[i]);
    dfs(1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10207916.html