BZOJ3172 [Tjoi2013]单词 【AC自动机】

3172: [Tjoi2013]单词

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 4293  Solved: 2083
[Submit][Status][Discuss]

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1



复习了一下AC自动机


#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
using namespace std;
const int maxn = 305,maxm = 1310005,INF = 1000000000;
char T[maxm];
int pos[maxn],ans[maxn],ch[maxm][26],last[maxm],f[maxm],N,siz = 0;;
vector<int> tag[maxm];
void insert(int p){
	int u = 0,id;
	for (int j = pos[p - 1]; j < pos[p]; j++){
		id = T[j] - 'a';
		u = ch[u][id] ? ch[u][id] : ch[u][id] = ++siz;
	}
	tag[u].push_back(p);
}
void getf(){
	queue<int> q;
	for (int i = 0; i < 26; i++) if (ch[0][i]) q.push(ch[0][i]);
	int u,v;
	while (!q.empty()){
		u = q.front();
		q.pop();
		for (int i = 0; i < 26; i++){
			v = ch[u][i];
			if (!v) ch[u][i] = ch[f[u]][i];
			else f[v] = ch[f[u]][i],q.push(v),last[v] = tag[f[v]].size() ? f[v]:last[f[v]];
		}
	}
}
void re(int u){
	while (u){
		for (unsigned int j = 0; j < tag[u].size();j++)
			ans[tag[u][j]]++;
		u = last[u];
	}
}
void AC(int p){
	int u = 0,id;
	for (int i = pos[p - 1]; i < pos[p]; i++){
		id = T[i] - 'a';
		u = ch[u][id];
		if (tag[u].size()) re(u);
		else if (last[u]) re(last[u]);
	}
}
int main()
{
	scanf("%d",&N);
	for (int i = 1; i <= N; i++){
		scanf("%s",T + pos[i - 1]);
		pos[i] = pos[i - 1] + strlen(T + pos[i - 1]);
		insert(i);
	}
	getf();
	REP(i,N) AC(i);
	REP(i,N) printf("%d
",ans[i]);
	return 0;
}


原文地址:https://www.cnblogs.com/Mychael/p/8282816.html