题目链接:https://vjudge.net/problem/HDU-3065
病毒侵袭持续中
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15743 Accepted Submission(s): 5343
Problem Description
小t非常感谢大家帮忙解决了他的上一个问题。然而病毒侵袭持续中。在小t的不懈努力下,他发现了网路中的“万恶之源”。这是一个庞大的病毒网站,他有着好多好多的病毒,但是这个网站包含的病毒很奇怪,这些病毒的特征码很短,而且只包含“英文大写字符”。当然小t好想好想为民除害,但是小t从来不打没有准备的战争。知己知彼,百战不殆,小t首先要做的是知道这个病毒网站特征:包含多少不同的病毒,每种病毒出现了多少次。大家能再帮帮他吗?
Input
第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。
Output
按以下格式每行一个,输出每个病毒出现次数。未出现的病毒不需要输出。
病毒特征码: 出现次数
冒号后有一个空格,按病毒特征码的输入顺序进行输出。
病毒特征码: 出现次数
冒号后有一个空格,按病毒特征码的输入顺序进行输出。
Sample Input
3
AA
BB
CC
ooxxCC%dAAAoen....END
Sample Output
AA: 2
CC: 1
Hint
Hit:
题目描述中没有被提及的所有情况都应该进行考虑。比如两个病毒特征码可能有相互包含或者有重叠的特征码段。
计数策略也可一定程度上从Sample中推测。
Source
Recommend
lcy
题解:
1.把每个病毒加入Trie树中,并记录其编号。
2.将“万恶之源”与Trie树进行匹配,统计每个病毒出现的次数。
注:在匹配的过程中,如果出现Trie树之外的字符,那么必定不能匹配,所以直接把指针指向root,然后继续下一个字符。
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const double EPS = 1e-6; 5 const int INF = 2e9; 6 const LL LNF = 9e18; 7 const int MOD = 1e9+7; 8 const int MAXN = 1e5+10; 9 10 //id为病毒的编号, sum[]用于记录每个病毒出现的次数 11 int id, sum[1010]; 12 struct Trie 13 { 14 const static int sz = 26, base = 'A'; 15 int next[MAXN][sz], fail[MAXN], end[MAXN]; 16 int root, L; 17 18 int newnode() 19 { 20 for(int i = 0; i<sz; i++) 21 next[L][i] = -1; 22 end[L++] = 0; 23 return L-1; 24 } 25 26 void init() 27 { 28 L = 0; 29 root = newnode(); 30 } 31 32 void insert(char buf[]) 33 { 34 int len = strlen(buf); 35 int now = root; 36 for(int i = 0; i<len; i++) 37 { 38 if(next[now][buf[i]-base] == -1) 39 next[now][buf[i]-base] = newnode(); 40 now = next[now][buf[i]-base]; 41 } 42 end[now] = id; 43 } 44 45 void build() 46 { 47 queue<int>Q; 48 fail[root] = root; 49 for(int i = 0; i<sz; i++) 50 { 51 if(next[root][i] == -1) 52 next[root][i] = root; 53 else 54 fail[next[root][i]] = root, Q.push(next[root][i]); 55 } 56 while(!Q.empty()) 57 { 58 int now = Q.front(); 59 Q.pop(); 60 for(int i = 0; i<sz; i++) 61 { 62 if(next[now][i] == -1) 63 next[now][i] = next[fail[now]][i]; 64 else 65 fail[next[now][i]] = next[fail[now]][i], Q.push(next[now][i]); 66 } 67 } 68 } 69 70 void query(char buf[]) 71 { 72 int len = strlen(buf); 73 int now = root; 74 for(int i = 0; i<len; i++) 75 { 76 //如果出现Trie树之外的字符,那么必定不能匹配,直接把指针指向root,然后进行下一个字符。 77 if(buf[i]<'A' || buf[i]>'Z') 78 { 79 now = root; 80 continue; 81 } 82 now = next[now][buf[i]-base]; 83 int tmp = now; 84 while(tmp != root) 85 { 86 if(end[tmp]) sum[end[tmp]]++; 87 tmp = fail[tmp]; 88 } 89 } 90 } 91 }; 92 93 Trie ac; 94 char buf[2000020], virus[1010][55]; 95 int main() 96 { 97 int n; 98 while(scanf("%d", &n)!=EOF) 99 { 100 ac.init(); 101 for(int i = 1; i<=n; i++) 102 { 103 id = i; 104 scanf("%s", virus[i]); 105 ac.insert(virus[i]); 106 } 107 ac.build(); 108 109 scanf("%s", buf); 110 memset(sum, 0, sizeof(sum)); 111 ac.query(buf); 112 113 for(int i = 1; i<=n; i++) 114 if(sum[i]) 115 printf("%s: %d ", virus[i], sum[i]); 116 } 117 return 0; 118 }