BZOJ.2882.工藝(後綴自動機 最小表示 map)
阿新 • • 發佈:2018-06-29
register tomato iter clas nlogn tor 字典序 problem 轉移
題目鏈接 BZOJ
洛谷
SAM求字符串的最小循環表示。
因為從根節點出發可以得到所有子串,所以每次找字典序最小的一個出邊走即可。因為長度問題把原串再拼接在後面一次。
需要用map存轉移。復雜度O(nlogn)。
當然還有O(n)的最小表示法。
(在BZOJ上慢的一批啊QAQ)
//73240kb 2496ms
#include <map>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=(3e5+5)*4;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
struct Suffix_Automaton
{
int n,s[N],las,tot,fa[N],len[N];
std::map<int,int> son[N];
void Insert(int c)
{
int p=las,np=++tot; len[las=np]=len[p]+1 ;
for(; p&&!son[p].count(c); p=fa[p]) son[p][c]=np;
if(!p) fa[np]=1;
else
{
int q=son[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot;
len[nq]=len[p]+1, son[nq]=son[q];
fa[nq]=fa[q], fa[q]=fa[np]=nq;
for (; son[p][c]==q; p=fa[p]) son[p][c]=nq;
}
}
}
void Build()
{
n=read(), las=tot=1;
for(int i=1; i<=n; ++i) Insert(s[i]=read());
for(int i=1; i<=n; ++i) Insert(s[i]);
}
void Solve()
{
std::map<int,int>::iterator it;
for(int i=1,p=1; i<=n; ++i)
it=son[p].begin(), p=it->second, printf("%d ",it->first);//別混了map的first(轉移)與second(son)啊
}
}sam;
int main()
{
sam.Build(), sam.Solve();
return 0;
}
BZOJ.2882.工藝(後綴自動機 最小表示 map)