bzoj3172 [Tjoi2013]单词
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3172
【题解】
考虑建出AC自动机,那么fail树上每个点的父亲为fail,父亲->儿子为后缀关系(父亲是儿子后缀)
那么走到父亲肯定走到了儿子,直接统计即可。
# include <queue> # 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 M = 1.6e6 + 10; const int mod = 1e9+7; int n; char t[M]; int v[M], ps[M]; vector<int> G[M]; struct ACM { int ch[M][26], fail[M], siz, isend[M]; inline void set() {siz = 0;} inline int ins(char *t) { int p = 0; for (int i=0; t[i]; ++i) { int c = t[i] - 'a'; if(!ch[p][c]) ch[p][c] = ++siz; p = ch[p][c]; v[p] ++; } return p; } queue<int> q; inline void build() { while(!q.empty()) q.pop(); for (int c=0; c<26; ++c) { int p = ch[0][c]; if(p) { fail[p] = 0; q.push(p); } } while(!q.empty()) { int top = q.front(); q.pop(); for (int c=0; c<26; ++c) { int p = ch[top][c]; if(!p) { ch[top][c] = ch[fail[top]][c]; continue; } q.push(p); int v = fail[top]; while(v && !ch[v][c]) v = fail[v]; fail[p] = ch[v][c]; } } } inline void getfail() { for (int i=1; i<=siz; ++i) G[fail[i]].push_back(i); } }S; inline void dfs(int x) { for (int i=0; i<G[x].size(); ++i) { int y = G[x][i]; dfs(y); v[x] += v[y]; } } int main() { cin >> n; S.set(); for (int i=1; i<=n; ++i) { scanf("%s", t); ps[i] = S.ins(t); } S.build(); S.getfail(); dfs(0); for (int i=1; i<=n; ++i) printf("%d\n", v[ps[i]]); return 0; }