工艺-后缀自动机
题目描述
题解
对于字符集大小不为常数的后缀自动机题,可以暴力建
m
a
p
map
map
首先倍长序列,对倍长过后的序列建后缀自动机,然后根据贪心,直接从根节点遍历n次输出答案即可(其实还是有点不懂)
(坑:数组必须开到1e6,不知为啥)
代码实现
#include<bits/stdc++.h>//SAM
#define M 1000009
using namespace std;
struct sam{
int fa,len;
map<int,int>ch;
}tr[M];
int n,last,rt,a[M],cnt;
void extend(int pos){
int np=++cnt,val=a[pos],p=last;
tr[np].len=pos,last=np;
while(p&&!tr[p].ch[val]) tr[p].ch[val]=np,p=tr[p].fa;
if(!p) tr[np].fa=rt;
else{
int q=tr[p].ch[val];
if(tr[q].len==tr[p].len+1) tr[np].fa=q;
else{
int nq=++cnt;
tr[nq].len=tr[p].len+1;
tr[nq].ch=tr[q].ch;
tr[nq].fa=tr[q].fa,tr[q].fa=tr[np].fa=nq;
while(p&&tr[p].ch[val]==q) tr[p].ch[val]=nq,p=tr[p].fa;
}
}
}
int main(){
scanf("%d",&n),last=rt=++cnt;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) a[i+n]=a[i];
for(int i=1;i<=n;i++) extend(i);
for(int i=1;i<=n;i++) extend(i+n);
int p=rt;
for(int i=1;i<=n;i++){
printf("%d ",tr[p].ch.begin()->first);//输出map中的第一个元素,必须用指针
p=tr[p].ch.begin()->second;//同上,第二个元素
}
return 0;
}
后记
该题也可以用最小表示法
推荐一个后缀自动机可视化的网站,可以帮助理解:https://yeah.moe/p/a8e74947/