1、 题目大意:一篇论文是由许多单词组成,现在想知道每个单词分别在论文中出现多少次。
2、分析:对着 广义后缀自动机的图看,我们就会发现玄机,答案不就是这个单词下的后缀个数吗?
于是建立自动机,然后求出right,统计答案就好,另外说一句,right集合用基数排序之后更新一下就好
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; struct SAM{ struct node{ int tranc[27], fa, len, right; } a[2002010]; int c[2002010], od[2002010]; int cnt, tail; SAM(){ tail = ++ cnt; } void insert(int k){ int p, np = ++ cnt, q, nq; a[np].len = a[tail].len + 1; a[np].right = 1; for(p = tail; p && !a[p].tranc[k]; p = a[p].fa) a[p].tranc[k] = np; if(!p) a[np].fa = 1; else{ q = a[p].tranc[k]; if(a[q].len == a[p].len + 1) a[np].fa = q; else{ a[nq = ++ cnt] = a[q]; a[q].fa = a[np].fa = nq; a[nq].len = a[p].len + 1; a[nq].right = 0; for(; a[p].tranc[k] == q; p = a[p].fa) a[p].tranc[k] = nq; } } tail = np; } void init(int m){ for(int i = 1; i <= cnt; i ++) c[a[i].len] ++; for(int i = 1; i <= m; i ++) c[i] += c[i - 1]; for(int i = cnt; i >= 1; i --) od[c[a[i].len] --] = i; for(int i = cnt; i >= 1; i --){ int x = od[i]; a[a[x].fa].right+=a[x].right; } return; } } sam; char str[2000100]; int tot; int main(){ int n; scanf("%d", &n); tot = -1; for(int i = 1; i <= n; i ++){ char ch = getchar(); while(ch < 'a' || ch > 'z') ch = getchar(); while('a' <= ch && ch <= 'z'){ str[++ tot] = ch; ch = getchar(); } str[++ tot] = 'z'+1; } tot ++; for(int i = 0; i < tot; i ++) sam.insert(str[i] - 'a'); sam.init(tot); int num; int o = 0; for(int i = 1; i <= n; i ++){ int now = 1, j; for(j = o; ((int)str[j] != 'z'+1) && (j < tot); j ++){ now = sam.a[now].tranc[str[j]-'a']; } o = j + 1; printf("%d\n", sam.a[now].right); } return 0; }