1. 程式人生 > >另一種保證單次插入迴文自動機複雜度的做法

另一種保證單次插入迴文自動機複雜度的做法

普通迴文自動機複雜度是均攤的。
對於單次插入複雜度有證明的迴文自動機插入,
\(\sum\)為字符集大小,翁文濤的論文裡提到了單次插入\(O(\sum)\)的記憶化,從理論上來說,可以通過主席樹優化到\(O(log\sum)\),但是程式碼量就增加了,而且對於26的字符集,這樣寫應該會變慢吧。
翻金策字串演算法選講的時候,偶然發現了一個淺顯的結論,迴文串的border等價於它的字尾迴文串。
那麼這就好辦了,直接利用border的性質,將暴力往上跳找fa改為一次跳一個等差數列找fa就好了。

int p=-1;
while (r-T[la].len-1<l||s[r-T[la].len-1]!=s[r]){
    if (p!=T[la].d){
        p=T[la].d;
        la=T[la].fa;
    }
    else la=T[T[la].df].fa;
}

其中\(T[la].d\)為他和他父親\(len\)的差值,\(T[la].df\)為他所在\(len\)等差數列的祖先,由border的性質,這樣單次插入最多跳\(log(n)\)次,同時不影響總的均攤複雜度。雖然單次插入複雜度不如論文中的演算法,但是不需要維護過多其他資訊,只需要維護十分有用的等差數列就可以了。
這樣,如果迴文自動機上的轉移邊用hash儲存,就可以得到一個單次插入\(O(log(n))\),插入字串均攤複雜度\(O(n)\),空間\(O(n)\)的做法。