简单地说,AC自动机就是可以匹配好多字符串的东西。。。。
其实就是在Trie树上做KMP。
fail[i]表示的是i节点代表的串的意义就是在Trie上出现过的最长后缀(当然不包括自己)所在的节点。
如果暴力找fail[i]的话会超级慢,所以我们可以把值为0的tr[i][j]赋为tr[fail[i]][j]。注意要按BFS序求fail[i],因为dep[i]>dep[fail[i]]。
然后就可以快乐地匹配啦!
TJOI2013 单词
#include<bits/stdc++.h>
using namespace std;
#define fp(i, b, e) for ( int i = b, I = e; i <= I; ++i )
#define fd(i, b, e) for ( int i = b, I = e; i >= I; --i )
#define go(i, b) for ( int i = b, v = to[b]; i; v = to[i = nxt[i]] )
#define i64 long long
inline bool cmin( int &x, int y ){ return x > y ? x = y, 1 : 0; }
inline bool cmax( int &x, int y ){ return x < y ? x = y, 1 : 0; }
const int _ = 1e6 + 55;
int N; string s[205];
int tr[_][26], num, fail[_], id[205], cnt[_];
vector<int> e[_];
queue<int> Q;
void Ins( int k, string s ){
int cur(0), d;
fp( i, 0, s.size() - 1 ){
d = s[i] - 'a';
if ( !tr[cur][d] ) tr[cur][d] = ++num;
cur = tr[cur][d];
} id[k] = cur;
}
void Build(){
fp( i, 0, 25 ) if ( tr[0][i] ) Q.push(tr[0][i]);
while( !Q.empty() ){
int t(Q.front()); Q.pop();
fp( i, 0, 25 ){
if ( tr[t][i] ){
fail[tr[t][i]] = tr[fail[t]][i];
Q.push(tr[t][i]);
} else tr[t][i] = tr[fail[t]][i];
}
}
}
void DFS( int u, int fa ){
for ( int v : e[u] ) if ( v != fa ){
DFS(v, u);
cnt[u] += cnt[v];
}
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N;
fp( i, 1, N ) cin >> s[i], Ins(i, s[i]);
Build();
fp( i, 1, N ){
int cur(0);
fp( j, 0, s[i].size() - 1 )
cur = tr[cur][(int)(s[i][j] - 'a')], ++cnt[cur];
}
fp( i, 1, num ) e[fail[i]].push_back(i), e[i].push_back(fail[i]);
DFS(0, 0);
fp( i, 1, N ) printf( "%d\n", cnt[id[i]] );
return 0;
} 
京公网安备 11010502036488号