后缀自动机小结 (spoj 8222)

来源:互联网 发布:手机语音拨号软件 编辑:程序博客网 时间:2024/06/05 11:12
后缀自动机理解关键点:
1. 根到任意一个结点都可以形成S的一个子串,并且S的所有子串都可以通过这种方式形成;
2. 到达该节点是所有路径就是一个right集合,一个拥有相同后缀的right集合;
3. 设某子串为str,这后缀自动机读入str后能到达的状态为right(str),即str在S中出现的位置的集合;
4. 假设node[b].fa = a,则状态a可以代替状态b进行识别。

附图:


更详细的资料:
http://wenku.baidu.com/view/90f22eec551810a6f4248606.html
http://blog.sina.com.cn/s/blog_7812e98601012cim.html

例题:

spoj 8222

题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。求F(1)..F(Length(S))。

限制:|S| <= 250000

/*spoj 8222  题意:  给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。求F(1)..F(Length(S))。  限制:  |S| <= 250000  思路:  后缀自动机  后缀自动机理解关键点:  1. 根到任意一个结点都可以形成S的一个子串,并且S的所有子串都可以通过这种方式形成;  2. 到达该节点是所有路径就是一个right集合,一个拥有相同后缀的right集合;  3. 设某子串为str,这后缀自动机读入str后能到达的状态为right(str),即str在S中出现的位置的集合;  4. 假设node[b].fa = a,则状态a可以代替状态b进行识别。 */#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;const int N = 250005;//注意,后缀自动机的节点要开2倍n,根是从1开始的struct SAM {struct Node {int fa, ch[27];int val, ans;void init() {fa = 0;memset(ch, 0, sizeof(ch));val = 0;ans = 0;}} node[2 * N];int tot;int new_node() {node[++tot].init();return tot;}int root, last;void init() {tot = 1;root = last = 1;node[0].init();node[root].init();}void add(int x) {int p = last;int np = new_node(); node[np].val = node[p].val + 1;while(p && node[p].ch[x] == 0)node[p].ch[x] = np, p = node[p].fa;if(p == 0)node[np].fa = root;else {int q = node[p].ch[x];if(node[p].val + 1 == node[q].val)node[np].fa = q;else {int nq = new_node(); node[nq].val = node[p].val + 1;memcpy(node[nq].ch, node[q].ch, sizeof(node[nq].ch));node[nq].fa = node[q].fa;node[q].fa = node[np].fa = nq;while(p && node[p].ch[x] == q)node[p].ch[x] = nq, p = node[p].fa;}}last = np;}void debug() {for(int i = 1; i <= tot; ++i) {printf("id=%d, fa=%d, step=%d, ch=[ ", i, node[i].fa, node[i].val);for(int j = 0; j < 26; ++j) {if(node[i].ch[j])printf("%c,%d ", j+'a', node[i].ch[j]);}puts("]");}}void gao(int);}sam;char str[N];int du[2 * N];int cnt[2 * N];int ans[N];void init() {sam.init();memset(du, 0, sizeof(du));memset(ans, 0, sizeof(ans));memset(cnt, 0, sizeof(cnt));}int que[2 * N], fr, ta;void SAM::gao(int n) {for(int i = 1; i <= tot; ++i) {++du[node[i].fa];}int tmp = root;for(int i = 0; i < n; ++i) {tmp = node[tmp].ch[str[i] - 'a'];cnt[tmp] = 1;}fr = ta = 0;for(int i = 1; i <= tot; ++i) {if(du[i] == 0) {que[ta++] = i;}}while(fr != ta) {int now = que[fr++];--du[node[now].fa];cnt[node[now].fa] += cnt[now];if(du[node[now].fa] == 0) {que[ta++] = node[now].fa;}}for(int i = 2; i <= tot; ++i) {ans[node[i].val] = max(ans[node[i].val], cnt[i]);}for(int i = n - 1; i >= 1; --i) {ans[i] = max(ans[i], ans[i + 1]);}for(int i = 1; i <= n; ++i) {printf("%d\n", ans[i]);}}int main() {while(gets(str)) {int n = strlen(str);init();for(int i = 0; i < n; ++i)sam.add(str[i] - 'a');//sam.debug();sam.gao(n);}return 0;}


0 0
原创粉丝点击