bzoj3172 [Tjoi2013]单词

[Tjoi2013]单词

Time Limit: 10 Sec Memory Limit: 512 MB

Description

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

Input

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

Output

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

Sample Input

3

a

aa

aaa

Sample Output

6

3

1

<br >
<br >
<br >
<br >
<br >
<br >
<br >

由KMP转向AC自动机。。。。感觉还可以,自动脑补.jpg
大概就是你一个串走了次他的fail能连接的地方显然也可以走,你倒着搞一波就差不多了。。。


#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
struct lpl{
	int sum, fail, ch[30];
}node[maxn];
int n, len, cnt, tot, pos[205], Q[maxn];
char s[maxn];

inline void putit()
{
	scanf("%d", &n);	int now, lin; cnt = 1;
	for(int i = 1; i <= n; ++i){
		scanf("%s", s + 1); len = strlen(s + 1); now = 1;
		for(int j = 1; j <= len; ++j){
			lin = s[j] - 'a' + 1;
			if(!node[now].ch[lin]){node[now].ch[lin] = ++cnt;}
			now = node[now].ch[lin]; node[now].sum++;
			if(j == len) pos[i] = now;
		}		
	}
}

inline void workk()
{
	queue<int> q;
	q.push(1); int now, t;
	while(!q.empty()){
		now = q.front(); q.pop();
		Q[++tot] = now;
		for(int i = 1; i <= 26; ++i){
			if(!node[now].ch[i]) continue;
			q.push(node[now].ch[i]);
			if(now == 1){
				node[node[now].ch[i]].fail = 1;
				continue;
			}
			t = node[now].fail;
			while(!node[t].ch[i] && t) t = node[t].fail;
			if(!t) node[node[now].ch[i]].fail = 1;
			else node[node[now].ch[i]].fail = node[t].ch[i];
		}
	}
}

inline void print()
{
	for(int i = tot; i >= 1; --i)	node[node[Q[i]].fail].sum += node[Q[i]].sum;
	for(int i = 1; i <= n; ++i) printf("%d\n", node[pos[i]].sum);
}

int main()
{
	putit();
	workk();
	print();
	return 0;
}

posted @ 2018-05-18 20:44  沛霖  阅读(127)  评论(0编辑  收藏  举报