hihocoder1445 后缀自动机二·重复旋律5

mac2022-06-30  26

传送门:http://hihocoder.com/problemset/problem/1445

【题解】

大概看了一天的后缀自动机,总算懂了一些

这篇文章写的非常好,诚意安利:Suffix Automaton Tutorial - Hunt Zhan

我就是看了这个大概懂了。

整个过程大概是:每次插入一个state可能会分裂原有的state的transition,就维护这个transition即可。

要用par[x]记录suffix-link是谁。

过程中可以不用记录minlen,因为$minlen[i] = maxlen[par[i]] + 1$,这点非常重要。

这题前面写了后缀自动机,然后上面像统计子树一样统计,后来发现,复杂度是$O(n * 26)$,似乎太大了,TLE了。

其实后缀自动机的每个state都含有若干子串,所有state的含有子串个数之和就是总个数了。

每个state含有子串个数为$maxlen[i] - minlen[i]$,这里把$minlen[i]$替换成$maxlen[par[i]] + 1$即可,不需要再求$minlen[i]$。

这样复杂度就差不多$O(n)$了,常数小了。

# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int N = 1e6 + 10, M = 2e6 + 3; const int mod = 1e9+7; char str[N]; struct SAM { int ch[M][26], par[M], ml[M]; int siz, rt, last; inline void set() { siz = rt = last = 1; memset(ch, 0, sizeof ch); memset(par, 0, sizeof par); memset(ml, 0, sizeof ml); } inline void extend(int c) { int p = last, cur = ++siz; ml[cur] = ml[p] + 1; for (; p && !ch[p][c]; p = par[p]) ch[p][c] = cur; if(!p) par[cur] = rt; else { int q = ch[p][c]; if(ml[q] == ml[p] + 1) par[cur] = q; else { int sq = ++siz; par[sq] = par[q]; for (int i=0; i<26; ++i) ch[sq][i] = ch[q][i]; ml[sq] = ml[p] + 1; par[q] = par[cur] = sq; for (; p && ch[p][c] == q; p = par[p]) ch[p][c] = sq; } } last = cur; } }S; /* ll f[M]; inline void dfs(int x) { f[x] = 1; for (int i=0; i<26; ++i) { if(!S.ch[x][i]) continue; dfs(S.ch[x][i]); f[x] += f[S.ch[x][i]]; } } */ int main() { scanf("%s", str+1); S.set(); for (int i=1; str[i]; ++i) S.extend(str[i] - 'a'); ll ans = 0; for (int i=1; i<=S.siz; ++i) { if(i == S.rt) continue; ans += S.ml[i] - S.ml[S.par[i]]; } cout << ans; return 0; } View Code

 

转载于:https://www.cnblogs.com/galaxies/p/hihocoder1445.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)