病毒侵袭持续中 HDU - 3065 AC自动机

小t非常感谢大家帮忙解决了他的上一个问题。然而病毒侵袭持续中。在小t的不懈努力下,他发现了网路中的“万恶之源”。这是一个庞大的病毒网站,他有着好多好多的病毒,但是这个网站包含的病毒很奇怪,这些病毒的特征码很短,而且只包含“英文大写字符”。当然小t好想好想为民除害,但是小t从来不打没有准备的战争。知己知彼,百战不殆,小t首先要做的是知道这个病毒网站特征:包含多少不同的病毒,每种病毒出现了多少次。大家能再帮帮他吗?

Input第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。
Output按以下格式每行一个,输出每个病毒出现次数。未出现的病毒不需要输出。
病毒特征码: 出现次数
冒号后有一个空格,按病毒特征码的输入顺序进行输出。
Sample Input

3
AA
BB
CC
ooxxCC%dAAAoen....END

Sample Output

AA: 2
CC: 1

        
 

Hint

Hit:
题目描述中没有被提及的所有情况都应该进行考虑。比如两个病毒特征码可能有相互包含或者有重叠的特征码段。
计数策略也可一定程度上从Sample中推测。

 

题解:

病毒侵袭 HDU - 2896  差不多

注意:

1:gets读入
2:由于目标串中匹配的时候有很多字符,但是你又不能去掉他们,但是next数组开到127的话太消耗内存,我的做法除了 'A'-'Z' 的字符之外的所有字母都变成 'Z'+1 ,这样的话只要开 next[27] 就够了。
 
  1 /*
  2 代码中:
  3 叶节点:代表此节点下没有子节点
  4 根节点:就是树的根
  5 子节点:就是这个节点的直接相连的节点(直系节点)
  6 
  7 此代码:
  8 用题目所给模式串构成一颗字典树
  9 然后找出来给出的待求串中每种模式串出现
 10 
 11 */
 12 #include<stdio.h>
 13 #include<iostream>
 14 #include<string.h>
 15 #include<algorithm>
 16 #include<queue>
 17 using namespace std;
 18 const int maxn=5e4+10;
 19 const int N=28;
 20 typedef long long ll;
 21 int v[1005];
 22 char ss[1005][55];
 23 struct Trie
 24 {
 25     int next[maxn][N],fail[maxn],ends[maxn];
 26     int root,L;
 27     int New_node() //创建一个新节点
 28     {
 29         for(int i=0; i<N; ++i)
 30         {
 31             next[L][i]=-1;
 32         }
 33         ends[L++]=0;
 34         return L-1;
 35     }
 36     void init()  //创建根节点
 37     {
 38         L=0;
 39         root=New_node();
 40     }
 41     void inserts(char s[],int x)  //往字典树里面插入新字符串
 42     {
 43         int len=strlen(s);
 44         int now=root;
 45         for(int i=0; i<len; ++i)
 46         {
 47             if(next[now][s[i]-'A']==-1)
 48                 next[now][s[i]-'A']=New_node();
 49             now=next[now][s[i]-'A'];
 50         }
 51         ends[now]=x;
 52     }
 53     void build()
 54     {
 55         queue<int>r;
 56         fail[root]=root;
 57         for(int i=0; i<N; ++i)
 58         {
 59             if(next[root][i]==-1)
 60             {
 61                 next[root][i]=root;
 62             }
 63             else
 64             {
 65                 fail[next[root][i]]=root;
 66                 r.push(next[root][i]);
 67             }
 68         }
 69         while(!r.empty())
 70         {
 71             int now=r.front();
 72             r.pop();
 73             for(int i=0; i<N; ++i)
 74             {
 75                 if(next[now][i]==-1)
 76                 {
 77                     next[now][i]=next[fail[now]][i];  //叶节点处没有设置失败节点而是往next上接了一段,这个时候
 78                     //这个fail里面的值已经在下面的else里面放过东西了
 79                 }
 80                 else
 81                 {
 82                     fail[next[now][i]]=next[fail[now]][i];  //此节点的子节点的失败节点就是此节点失败节点对应字符位置
 83                     r.push(next[now][i]);
 84                 }
 85             }
 86         }
 87     }
 88     void query(char s[])
 89     {
 90         int len=strlen(s);
 91         int now=root;
 92         //int res=0;
 93         for(int i=0; i<len; ++i)
 94         {
 95             now=next[now][s[i]-'A']; //这个now就保证了我们找的肯定是这个字符串中的一部分
 96             int temp=now; //这就是一直找,找到了就加1,找不到就通过失败节点看其他地方能不能找到
 97             while(temp!=root)
 98             {
 99                 if(ends[temp])
100                 {
101                     v[ends[temp]]++;
102                 }
103                 //res+=ends[temp];
104                 //ends[temp]=0;
105                 temp=fail[temp];
106             }
107         }
108         //return res;
109     }
110 };
111 char s[2000010];
112 Trie ac;
113 int main()
114 {
115 //    int t;
116 //    scanf("%d",&t);
117 //    while(t--)
118 //    {
119     int n;
120     while(~scanf("%d",&n))
121     {
122         memset(v,0,sizeof(v));
123         ac.init();
124         for(int j=1; j<=n; ++j)
125         {
126             scanf("%s",ss[j]);
127             int len=strlen(ss[j]);
128             for(int i=0; i<len; ++i)
129             {
130                 if(ss[j][i]>'Z' || ss[j][i]<'A')
131                 {
132                     ss[j][i]='A'+27;
133                 }
134             }
135             ac.inserts(ss[j],j);
136         }
137         getchar();
138         ac.build();
139         gets(s);
140         int len=strlen(s);
141         for(int i=0; i<len; ++i)
142         {
143             if(s[i]>'Z' || s[i]<'A')
144             {
145                 s[i]='A'+27;
146             }
147         }
148         //printf("**\n");
149         ac.query(s);
150         //printf("*");
151         for(int i=1; i<=n; ++i)
152         {
153             if(v[i])
154             {
155                 printf("%s: %d\n",ss[i],v[i]);
156             }
157         }
158     }
159 
160 //   }
161     return 0;
162 }

 

 

 

 

posted @ 2019-12-12 15:24  kongbursi  阅读(169)  评论(0编辑  收藏  举报