病毒侵袭持续中(HDU-3065)
Problem Description
小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
思路:
統計每個模版在文本串中出現次數,當用文本匹配時,每發現一個單詞節點 i,就將對應的 res[val[i]]++,最后按順序輸出即可,此外由于字符為 ASCII 碼,因此字典樹的第二維要開到 128
Source Program
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #define PI acos(-1.0) #define E 1e-9 #define INF 0x3f3f3f3f #define LL long long const int MOD=10007; const int N=500000+5; const int dx[]= {-1,1,0,0}; const int dy[]= {0,0,-1,1}; using namespace std; int res[N];//記錄結果 struct AC_Automata{int tire[N][128];//字典樹int val[N];//字符串結尾標記int fail[N];//失配指針int last[N];//last[i]=j表j節點表示的單詞是i節點單詞的后綴,且j節點是單詞節點int tot;//編號void init(){//初始化0號點tot=1;val[0]=fail[0]=last[0]=0;memset(tire[0],0,sizeof(tire[0]));}void insert(char *s,int v){//構造trie與val數組,v需非0,表示一個單詞節點int len=strlen(s);int root=0;for(int i=0;i<len;i++){int id=s[i];if(tire[root][id]==0){tire[root][id]=tot;memset(tire[tot],0,sizeof(tire[tot]));val[tot++]=0;}root=tire[root][id];}val[root]=v;}void build(){//構造fail與lastqueue<int> q;last[0]=fail[0]=0;for(int i=0;i<128;i++){int root=tire[0][i];if(root!=0){fail[root]=0;last[root]=0;q.push(root);}}while(!q.empty()){//bfs求failint k=q.front();q.pop();for(int i=0;i<128;i++){int u=tire[k][i];if(u==0)continue;q.push(u);int v=fail[k];while(v && tire[v][i]==0)v=fail[v];fail[u]=tire[v][i];last[u]=val[fail[u]]?fail[u]:last[fail[u]];}}}void print(int i){//遞歸打印與結點i后綴相同的前綴節點編號if(val[i]){res[val[i]]++;print(last[i]);}}void query(char *s){//匹配int len=strlen(s);int j=0;for(int i=0;i<len;i++){int id=s[i];while(j && tire[j][id]==0)j=fail[j];j=tire[j][id];if(val[j])print(j);else if(last[j])print(last[j]);}} }ac; char P[1000][1000]; char T[2000000+10]; int main(){int n;while(scanf("%d",&n)!=EOF&&n){memset(res,0,sizeof(res));ac.init();for(int i=1;i<=n;i++){scanf("%s",P[i]);ac.insert(P[i],i);}ac.build();scanf("%s",T);ac.query(T);for(int i=1;i<=n;i++)if(res[i])printf("%s: %d\n",P[i],res[i]);}return 0; }?
總結
以上是生活随笔為你收集整理的病毒侵袭持续中(HDU-3065)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一般图最大匹配(UOJ-79)
- 下一篇: 数论 —— 约数