病毒侵袭持续中
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 16472 Accepted Submission(s):
5572
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中推测。1 /* 2 hdu 3065 题意很简单 3 */ 4 #include <iostream> 5 #include<string.h> 6 #include<stdlib.h> 7 using namespace std; 8 9 int biaoshi[1010]; 10 char chuan[1100][55]; 11 const int kind = 26; //!!!!!!!!!!!!!!!!!! 12 13 struct node{ 14 node *fail; //失败指针 15 node *next[kind]; 16 int count; //是否为该单词的最后一个节点 17 node(){ //构造函数初始化 18 fail=NULL; 19 count=0; 20 memset(next,NULL,sizeof(next)); 21 } 22 }*q[50000]; //队列,方便用于bfs构造失败指针 23 char keyword[510]; //输入的单词 24 char str[2000010]; //模式串 25 int head,tail; //队列的头尾指针 26 27 void insert(char *str,node *root,int no){ 28 node *p=root; 29 int i=0,index; 30 while(str[i]){ 31 index=str[i]-'A'; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 32 if(p->next[index]==NULL) p->next[index]=new node(); 33 p=p->next[index]; 34 i++; 35 } 36 p->count=no;//初始化为0,++后为1,表示是一个单词的结尾!!!!!!!!!!!!!!!!! 37 } 38 void build_ac_automation(node *root) 39 { 40 int i; 41 root->fail=NULL; 42 q[head++]=root; 43 while(head!=tail) 44 { 45 node *temp=q[tail++];//拿到一个节点 46 node *p=NULL; 47 for(i=0;i<26;i++)//!!!!!!!!!!!!!!!!!!!!!!!!!!!! 48 { 49 if(temp->next[i]!=NULL)//若其i孩子非空 50 { 51 if(temp==root) //他自己是头,其孩子的失败指针指向头 52 temp->next[i]->fail=root; 53 else{ //普通节点 54 p=temp->fail; //指向自己的失败指针 55 while(p!=NULL) 56 { 57 if(p->next[i]!=NULL)//失败指针有i孩子 58 { 59 temp->next[i]->fail=p->next[i]; //当前节点的i孩子的失败指针指向失败指针的i孩子,然后跳出 60 break; 61 } 62 p=p->fail; //继续找失败指针 63 } 64 if(p==NULL) //若失败指针为空 65 temp->next[i]->fail=root; //当前节点的i孩子的失败指针指向头 66 } 67 q[head++]=temp->next[i]; //进去的都是定义过失败指针的,故此过程是给其孩子定义失败指针 68 } 69 } 70 } 71 } 72 int query(node *root) 73 { 74 int i=0,cnt=0,index,len=strlen(str); 75 node *p=root; 76 while(str[i]) 77 { 78 index=str[i]-'A'; //计算孩子的位置!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 79 if(index<0||index>25)//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 80 { 81 p=root; 82 i++; 83 continue; 84 } 85 while(p->next[index]==NULL && p!=root) 86 p=p->fail; //若没有i孩子节点,通过失败指针找与这之前相同的有i孩子的节点 87 p=p->next[index]; //指向其i孩子 88 p=(p==NULL)?root:p; 89 node *temp=p; 90 while(temp!=root && temp->count) 91 { 92 if(temp->count)//主要是改这里!!!!!!!!!!!!!!!!!!!!!!!!!!! 93 { 94 cnt++; 95 ++biaoshi[temp->count]; 96 } 97 temp=temp->fail; 98 } 99 i++; 100 } 101 return cnt; 102 } 103 int cmp(const void *a,const void *b) 104 { 105 int *c=(int*)a,*d=(int*)b; 106 return *c-*d; 107 } 108 void print(int ji,int na,int n) 109 { 110 111 printf("web %d:",na); 112 for(int i=1;i<=n;++i) 113 { 114 if(biaoshi[i]) 115 { 116 printf(" %d",i); 117 } 118 } 119 printf(" "); 120 } 121 int main(){ 122 int n,t,i,j=0; 123 while(scanf("%d",&n)!=EOF) 124 { 125 head=tail=0; 126 node *root=new node(); 127 128 getchar(); 129 for(i=1;i<=n;i++) 130 { 131 gets(keyword); 132 strcpy(chuan[i],keyword); 133 insert(keyword,root,i); 134 } 135 build_ac_automation(root); 136 memset(biaoshi,0,sizeof(biaoshi)); 137 scanf("%s",str); 138 query(root); 139 for(i=1;i<=n;i++) 140 { 141 if(biaoshi[i]) 142 { 143 printf("%s: %d ",chuan[i],biaoshi[i]); 144 } 145 } 146 //printf("total: %d ",j); 147 } 148 return 0; 149 }