1. 程式人生 > >BZOJ.2882.工藝(後綴自動機 最小表示 map)

BZOJ.2882.工藝(後綴自動機 最小表示 map)

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)