病毒侵襲持續中 HDU
阿新 • • 發佈:2018-12-21
小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中推測。 AC自動機模板題
只有一個文字串進行匹配,題目要求記錄文字串中出現多少個
不用做標記,直接遍歷到底即可。
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<iostream> using namespace std; const int maxn=5e4+7; const int branch=27; queue<int> mmp; int val[1010];//存放病毒特徵碼出現的次數 class AcTireNode { public: int next[branch]; int id,flag;//0為初始值 num記錄該病毒編號 flag記錄該節點被flag編號的文字遍歷了 int fail; void clear() { fail=0; for(int i=0; i<branch; ++i) next[i]=-1; id=flag=0; } }; class AcTire { private: AcTireNode *node; int top; public: AcTire() { node=new AcTireNode[maxn]; node[0].clear(); top=0; } int hash_letter(char c) { if(c>='A'&&c<='Z') return c-'A'; return 26; } void insert(char *s,int num) { int now=0; while(*s) { int i=hash_letter(*s); if(node[now].next[i]==-1) { node[now].next[i]=++top; node[top].clear(); } now=node[now].next[i]; ++s; } node[now].id=num; } void Bulid_fail()//作用實現:找到每個節點所代表字串的最大匹配 { int now,to; for(int i=0; i<branch; ++i) { if(node[0].next[i]!=-1) mmp.push(node[0].next[i]); } while(!mmp.empty()) { now=mmp.front(); mmp.pop(); for(int i=0; i<branch; ++i) { if(node[now].next[i]!=-1) { mmp.push(node[now].next[i]); to=node[now].fail; while(to>0&&node[to].next[i]==-1) to=node[to].fail; if(node[to].next[i]!=-1) to=node[to].next[i]; node[node[now].next[i]].fail=to; } } } } void Find_tx(char *tx)//計算文字串中所有病毒特徵碼出現的次數 { int now=0; int to; while(*tx) { int i=hash_letter(*tx); while(now>0&&node[now].next[i]==-1) now=node[now].fail; if(node[now].next[i]!=-1)//有匹配的字尾 { now=node[now].next[i]; to=now;//開始找所有後綴匹配 while(to>0)//這個節點 曾經是否被這個字串 遍歷過 { if(node[to].id) val[node[to].id]++; to=node[to].fail; } } ++tx; } } void init() { top=0; node[0].clear(); } ~AcTire() { delete []node; } }; char tx[2001000],str[1010][60]; int main() { AcTire dch; int n; while(~scanf("%d",&n)) { dch.init(); for(int i=1; i<=n; ++i) { scanf("%s",str[i]); dch.insert(str[i],i); } dch.Bulid_fail(); scanf("%s",tx); memset(val,0,sizeof(val)); dch.Find_tx(tx); for(int i=1;i<=n;++i) { if(val[i]) printf("%s: %d\n",str[i],val[i]); } } return 0; }