HDU5880 Family View(2016青岛网络赛 AC自动机)

时间:2021-01-20 07:42:02

题意:将匹配的串用‘*’代替

tips:

1 注意内存的使用,据说g++中指针占8字节,c++4字节,所以用g++交会MLE

2 注意这种例子,

1
2
abcd
bc
abc

故失败指针要一直往下走,否则会丢弃一些串

3 当出现非英文字符时应先将指针指向根节点,否则出现

1
1
cy
c,,,,,,,y

时结果为c,,,,,,**(由不止一种Bug造成的),正确的应为c,,,,,,,y,然而很多题解这样也过了~

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<utility>
using namespace std;
typedef long long LL;
int Hash[128]; const int N = 1000008, CH = 26;
struct Trie{
Trie *next[CH];
Trie *fail;
int len;
}; int flag[N]; char str[N]; class ACauto{ Trie tree[N];
private:
int nxt;
Trie *root; public:
void init(){
root = &tree[0];
nxt=0;
memset(&tree[0], 0, sizeof(Trie));
memset(flag, 0, sizeof(flag));
} void insert(char *s){
Trie *p = root;
int i;
for(i = 0; s[i]; i++){
int c = Hash[s[i]];
if(!p -> next[c]){
memset(&tree[++nxt], 0, sizeof(Trie));
p -> next[c] = &tree[nxt];
}
p = p -> next[c];
}
//p -> cnt = 1;
//p -> cnt++;//用于统计
p -> len = i; } void build(){
queue<Trie *> q;
q.push(root);
root -> fail = NULL;
while(!q.empty()){
Trie *now = q.front();
q.pop();
for(int i = 0; i < CH; i++){
Trie *son = now -> next[i];
Trie *tp = (now == root)? root: now -> fail->next[i];
if(son == NULL){
now -> next[i] = tp;//Trie图
}else{
son -> fail = tp;
//状态合并(如一个串是另一个串的子串则值域可以合并)
//son -> cnt += son -> fail -> cnt;
q.push(son);
}
}
}
} //查询匹配次数
void query(char *s){
Trie *now = root;
for(int i = 0; s[i]; i++){
int c = Hash[s[i]];
if(c == -1){
//注意,要将now赋值为root
now = root;
continue;
}
now = now -> next[c];
Trie *p = now;
while(p != root){
if(p -> len){
flag[i - p -> len + 1]--;
flag[i + 1]++;
}
p = p -> fail;
} }
}
}ac; int main(){
fill(Hash, Hash + 128, -1);
for(int i = 'a'; i <= 'z'; i++){
Hash[i] = i - 'a';
} for(int i = 'A'; i <= 'Z'; i++){
Hash[i] = i - 'A';
} int t;
cin >>t;
while(t--){
ac.init();
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%s", str);
ac.insert(str);
}
ac.build();
getchar();
gets(str);
ac.query(str);
LL cnt = 0;
for(int i = 0; str[i]; i++){
cnt += flag[i];
if(cnt >= 0){
putchar(str[i]);
}else{
putchar('*');
} }
printf("\n");
} return 0;
}