单词
C. 单词
题目描述
输入格式
输出格式
样例
数据范围与提示
【题解】
本来以为是个板子题,然后发现并不是。开始居然没有理解题目……文章就是所有的单词合起来,中间加空格,但是空格很碍事,可以一个单词一个单词地匹配。
这个题让我重新思考了一下AC自动机……一开始我是通过ask操作通过调fail指针来更新count,然后T90,有一个比较恶心的点是每个字母的fail指针都是他的父亲节点,然后就死了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; struct trie { int count; trie *next[26],*fail; trie() { count=0; fail=NULL; for(int i=0;i<26;i++) next[i]=NULL; } }*q[10000000],*root; int head,tail; trie *loc[210]; int n; char keyword[210][1000000]; void insert(char s[],trie *root,int t) { trie *p=root; int i=0,index; while(s[i]) { index=s[i]-'a'; if(p->next[index]==NULL)p->next[index]=new trie(); p=p->next[index]; i++; } loc[t]=p; } void build_ac(trie *root) { q[++tail]=root; while(head!=tail) { trie *p=q[++head]; trie *temp=NULL; for(int i=0;i<26;i++) if(p->next[i]!=NULL) { if(p==root)p->next[i]->fail=root; else { temp=p->fail; while(temp!=NULL) { if(temp->next[i]!=NULL) { p->next[i]->fail=temp->next[i]; break; } temp=temp->fail; } if(temp==NULL)p->next[i]->fail=root; } q[++tail]=p->next[i]; } } } void ask(trie *root,char str[]) { int i=0,index,cnt=0; trie *p=root; while(str[i]) { index=str[i]-'a'; while(p!=root && p->next[index]==NULL)p=p->fail; p=p->next[index]; if(p==NULL)p=root; trie *temp=p; while(temp!=root) { temp->count++; temp=temp->fail; } i++; } } signed main() { // freopen("in.txt","r",stdin); scanf("%d",&n); trie *root=new trie(); for(int i=1;i<=n;i++) { scanf("%s",keyword[i]); insert(keyword[i],root,i); } build_ac(root); for(int i=1;i<=n;i++) ask(root,keyword[i]); for(int i=1;i<=n;i++) printf("%d\n",loc[i]->count); }
其实可以在插入一个单词的时候对于他的路径上的点的count+1,表示这个前缀又出现了一次,根据AC自动机的性质,可以从下往上把i节点的count加到i->fail去。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; struct trie { int count; trie *next[26],*fail; trie() { count=0; fail=NULL; for(int i=0;i<26;i++) next[i]=NULL; } }*q[10000000],*root; int head,tail; trie *loc[210]; int n; char keyword[210][1000000]; void insert(char s[],trie *root,int t) { trie *p=root; int i=0,index; while(s[i]) { p->count++; index=s[i]-'a'; if(p->next[index]==NULL){p->next[index]=new trie();} p=p->next[index]; i++; } p->count++; loc[t]=p; } void build_ac(trie *root) { q[++tail]=root; while(head!=tail) { trie *p=q[++head]; trie *temp=NULL; for(int i=0;i<26;i++) if(p->next[i]!=NULL) { if(p==root)p->next[i]->fail=root; else { temp=p->fail; while(temp!=NULL) { if(temp->next[i]!=NULL) { p->next[i]->fail=temp->next[i]; break; } temp=temp->fail; } if(temp==NULL)p->next[i]->fail=root; } q[++tail]=p->next[i]; } } } signed main() { // freopen("word10.in","r",stdin); scanf("%d",&n); trie *root=new trie(); for(int i=1;i<=n;i++) { scanf("%s",keyword[i]); insert(keyword[i],root,i); } build_ac(root); for(int i=tail;i>0;i--) { trie *temp=q[i]; if(temp->fail!=NULL)temp->fail->count+=temp->count; } for(int i=1;i<=n;i++) printf("%d\n",loc[i]->count); }
波澜前,面不惊。