HDU 5880 Family View (AC自动机)
Family View
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2099 Accepted Submission(s): 441
Take an MMORPG game as an example, given a sentence T, and a list of forbidden words {P}, your job is to use '*' to subsititute all the characters, which is a part of the substring matched with at least one forbidden word in the list (case-insensitive).
For example, T is: "I love Beijing's Tiananmen, the sun rises over Tiananmen. Our great leader Chairman Mao, he leades us marching on."
And {P} is: {"tiananmen", "eat"}
The result should be: "I love Beijing's *********, the sun rises over *********. Our gr*** leader Chairman Mao, he leades us marching on."
The first line contains an integer n, represneting the size of the forbidden words list P. Each line of the next n lines contains a forbidden words P where P only contains lowercase letters.
The last line contains a string T.
#include <stdio.h> #include <algorithm> #include <iostream> #include <string.h> #include <queue> using namespace std; int vis[1000010]; struct Trie { int Next[1000010][26];//26是这里讨论26个小写字母的情况,根据情况修改 int fail[1000010],end[1000010];//end数组表示以该节点结尾的字符串的数量 int len[1000010]; int root,L;//L用来标记节点序号,以广度优先展开的字典树的序号 int newnode() //建立新节点 { for(int i = 0;i < 26;i++) Next[L][i] = -1; //将该节点的后继节点域初始化 len[L]=0; end[L++] = 0; return L-1; //返回当前节点编号 } void init() //初始化操作 { L = 0; root = newnode(); } void insert(char buf[]) { int Len = strlen(buf); int now = root; for(int i = 0;i < Len;i++) { if(Next[now][buf[i]-'a'] == -1) //如果未建立当前的后继节点,建立新的节点 Next[now][buf[i]-'a'] = newnode(); len[Next[now][buf[i]-'a']]=len[now]+1; now = Next[now][buf[i]-'a']; } end[now]=len[now];//以该节点结尾的字符串数量增加1 } void build() { queue<int>Q; //用广度优先的方式,将树层层展开 fail[root] = root; for(int i = 0;i < 26;i++) if(Next[root][i] == -1) Next[root][i] = root; else { fail[Next[root][i]] = root; Q.push(Next[root][i]); } while( !Q.empty() ) { int now = Q.front(); Q.pop(); end[now]=max(end[now],end[fail[now]]); for(int i = 0;i < 26;i++) if(Next[now][i] == -1) Next[now][i] = Next[fail[now]][i];//该段的最后一个节点匹配后,跳到拥有最大公共后缀的fail节点继续匹配 else { fail[Next[now][i]]=Next[fail[now]][i];//当前节点的fail节点等于它前驱节点的fail节点的后继节点 Q.push(Next[now][i]); } } } void solve(char buf[]) { int L=strlen(buf); int now=root; for(int i=0;i<L;i++) { now=Next[now][buf[i]-'a']; if(end[now]>0) { for(int j=i;j>i-end[now];j--) buf[j]='*'; } } for(int i=0;i<L;i++) { if(buf[i]!='*'&&vis[i]==1) printf("%c",buf[i]-32); else printf("%c",buf[i]); } printf("\n"); } }; char buf[1000010]; Trie ac; int main() { int t,n,ans; scanf("%d",&t); while(t--) { memset(vis,0,sizeof(vis)); ac.init(); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s",buf); ac.insert(buf); } ac.build(); getchar(); gets(buf); for(int i=0;i<strlen(buf);i++) { if(buf[i]>='A'&&buf[i]<='Z'){ buf[i]=buf[i]+32; vis[i]=1; } } ac.solve(buf); } return 0; }
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
int vis[1000010];
struct Trie
{
int Next[1000010][26];//26是这里讨论26个小写字母的情况,根据情况修改
int fail[1000010],end[1000010];//end数组表示以该节点结尾的字符串的数量
int len[1000010];
int root,L;//L用来标记节点序号,以广度优先展开的字典树的序号
int newnode() //建立新节点
{
for(int i = 0;i < 26;i++)
Next[L][i] = -1; //将该节点的后继节点域初始化
len[L]=0;
end[L++] = 0;
return L-1; //返回当前节点编号
}
void init() //初始化操作
{
L = 0;
root = newnode();
}
void insert(char buf[])
{
int Len = strlen(buf);
int now = root;
for(int i = 0;i < Len;i++)
{
if(Next[now][buf[i]-'a'] == -1) //如果未建立当前的后继节点,建立新的节点
Next[now][buf[i]-'a'] = newnode();
len[Next[now][buf[i]-'a']]=len[now]+1;
now = Next[now][buf[i]-'a'];
}
end[now]=len[now];//以该节点结尾的字符串数量增加1
}
void build()
{
queue<int>Q; //用广度优先的方式,将树层层展开
fail[root] = root;
for(int i = 0;i < 26;i++)
if(Next[root][i] == -1)
Next[root][i] = root;
else
{
fail[Next[root][i]] = root;
Q.push(Next[root][i]);
}
while( !Q.empty() )
{
int now = Q.front();
Q.pop();
end[now]=max(end[now],end[fail[now]]);
for(int i = 0;i < 26;i++)
if(Next[now][i] == -1)
Next[now][i] = Next[fail[now]][i];//该段的最后一个节点匹配后,跳到拥有最大公共后缀的fail节点继续匹配
else
{
fail[Next[now][i]]=Next[fail[now]][i];//当前节点的fail节点等于它前驱节点的fail节点的后继节点
Q.push(Next[now][i]);
}
}
}
void solve(char buf[])
{
int L=strlen(buf);
int now=root;
for(int i=0;i<L;i++)
{
now=Next[now][buf[i]-'a'];
if(end[now]>0)
{
for(int j=i;j>i-end[now];j--)
buf[j]='*';
}
}
for(int i=0;i<L;i++)
{
if(buf[i]!='*'&&vis[i]==1)
printf("%c",buf[i]-32);
else
printf("%c",buf[i]);
}
printf("\n");
}
};
char buf[1000010];
Trie ac;
int main()
{
int t,n,ans;
scanf("%d",&t);
while(t--)
{
memset(vis,0,sizeof(vis));
ac.init();
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",buf);
ac.insert(buf);
}
ac.build();
getchar();
gets(buf);
for(int i=0;i<strlen(buf);i++)
{
if(buf[i]>='A'&&buf[i]<='Z'){
buf[i]=buf[i]+32;
vis[i]=1;
}
}
ac.solve(buf);
}
return 0;
}