因為本人幾乎不會字尾陣列,所以遇到這種sa的模板題也要拿sam解決。
還是有一點思維難度的。
首先按照國際慣例,建反串的sam。
然後對於這個反串,我們考慮兩個字首哪乙個字典序小:因為是串是反的,所以要從後往前比較,那麼第乙個不相同的字元一定是兩個字首在字尾樹上的節點的lca的前一位。記其中乙個節點的任意乙個endpos的位置是\(end[i]\),lca的長度是\(len[x]\),那麼這個字元就是\(s[n - (end[i] - len[x])]\)。
這樣對於字尾樹上的每乙個節點,定義\(tp[i] = s[n - (end[i] - len[link[i]])] - 'a'\),然後以\(tp[i]\)為關鍵字進行基數排序就好了。
最後建出一棵新的樹,在上面dfs一遍即可。
luogu的板兒字符集太大,會mle,用map又tle了,而且不想手寫雜湊表,於是就沒放鏈結。
#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;
#define enter puts("")
#define space putchar(' ')
#define mem(a, x) memset(a, x, sizeof(a))
#define in inline
#define fore(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
typedef long long ll;
typedef double db;
const int inf = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 1.1e6 + 5;
inline ll read()
inline void write(ll x)
in void myfile()
int n;
char s[maxn];
int ans[maxn], acnt = 0;
struct edge
e[maxn << 1];
int head[maxn << 1], ecnt = -1;
in void addedge(int x, int y)
; head[x] = ecnt;
}struct sam
in void insert(int c, int x)
}las = now;
} int tp[maxn << 1], pos[maxn << 1], buc[maxn << 1];
in void solve()
in void dfs(int now)
in void _print()
}s;int main()
字尾自動機SAM
原理詳細的可以看史上最通俗的字尾自動機詳解 想看懂還是要花很久。實現 include include using namespace std const int maxn 2000010 struct node nodes maxn int las 1 tot 1 char st maxn void...
SAM 字尾自動機
好文 luogup3804 定義.對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。對給定字串s的字尾自動機是乙個最小化確定有限狀態自動機,它能夠接收字串s的所有字尾。某一狀態t 0被稱作初始狀態,由它能夠到達其餘所有狀態。自動機中的所有轉移 即有向邊 都被某種符號...
SAM 字尾自動機
這玩意還真的好玄學,看了半天,也就看了個大概吧 確實很妙 總算理解了parent樹,但是關於sam的dag的性質的證明並沒有看太懂,也沒有特別明白。update 又看了一會,原來是自己把定義搞錯了,字尾自動機其實是在滿足以下條件的最簡狀態,主要是難構造,掌握構造 就好了,證明就不管了c。條件如下 摘...