lightoj-1427:Substring Frequency
2013-07-27 14:37
417 查看
A string is a finite sequence of symbols that are chosen from an alphabet. In this problem you are given a string Tand n queries each with a string Pi,
where the strings contain lower case English alphabets only. You have to find the number of times Pi occurs as a substring of T.
Each case starts with a line containing an integer n (1 ≤ n ≤ 500). The next line contains the string T (1 ≤ |T| ≤ 106). Each of the next n lines contains
a string Pi (1 ≤ |Pi| ≤ 500).
刚开始没看题目,用kmp做,超时,后来看了一下主题,知道要用AC算法。
产生goto表,每次有新的模式,从起始状态开始,若存在相应的路径,则变换到该路径的状态,若没有,则创建新的状态,并转到该状态。
从0状态开始,0状态不会失败,1状态失败总是到0。然后层次遍历,对于fail[r],查看他的前一个状态p,p和r之间有‘a’边,若fail[p]存在‘a’的边,则fail[r]=goto(fail[p],a)。若没有,则检查fail[fail[p]],直到存在.0状态不会失败,确保迭代终止。
void parse()
{
int pos_gt=0;
for(int i=0;t[i]!='\0';++i)
{
while(gt[pos_gt][t[i]-'a']==-1)
pos_gt=fail[pos_gt];
pos_gt=gt[pos_gt][t[i]-'a'];
int tgt=pos_gt;
while(tgt!=0)
{
if(output[tgt]!=-1)
++output[tgt];
tgt=fail[tgt];
}
}
}
最后遍历主串。
where the strings contain lower case English alphabets only. You have to find the number of times Pi occurs as a substring of T.
Input
Input starts with an integer T (≤ 10), denoting the number of test cases.Each case starts with a line containing an integer n (1 ≤ n ≤ 500). The next line contains the string T (1 ≤ |T| ≤ 106). Each of the next n lines contains
a string Pi (1 ≤ |Pi| ≤ 500).
Output
For each case, print the case number in a single line first. Then for each string Pi, report the number of times it occurs as a substring of T in a single line.
|
|
2 5 ababacbabc aba ba ac a abc 3 lightoj oj light lit | Case 1: 2 3 1 4 1 Case 2: 1 1 0 |
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <vector> #include <list> using namespace std; char t[1000002]; int** gt; int* fail; int* output; int map[500]; char query[500][501]; int stateNum,maxStateNum; int queryNum; void generateGoto(); void generateFail(); void parse(); int main() { int caseNum; maxStateNum=250; fail=NULL; output=(int*)malloc(sizeof(int)*maxStateNum); gt=(int**)malloc(sizeof(int*)*maxStateNum); for(int i=0;i<maxStateNum;++i) gt[i]=(int*)malloc(sizeof(int)*26); for(int i=0;i<maxStateNum;++i) { for(int j=0;j<26;++j) gt[i][j]=-1; fail[i]=-1; output[i]=-1; } scanf("%d",&caseNum); for(int i=0;i<caseNum;++i) { scanf("%d",&queryNum); memset(t,0,1000002); scanf("%s",t); for(int j=0;j<queryNum;++j) { memset(query[j],0,501); scanf("%s",query[j]); } stateNum=0; generateGoto(); if(fail!=NULL) free(fail); fail=(int*)malloc(sizeof(int)*maxStateNum); for(int x=0;x<maxStateNum;++x) fail[x]=-1; generateFail(); parse(); printf("Case %d:\n",i+1); for(int p=0;p<queryNum;++p) printf("%d\n",output[map[p]]); for(int p=0;p<=stateNum;++p) { for(int q=0;q<26;++q) gt[p][q]=-1; fail[p]=output[p]=-1; } } return 0; }
void generateGoto() { for(int i=0;i<queryNum;++i) { int pos_gt=0; for(int j=0;query[i][j]!='\0';++j) { if(gt[pos_gt][query[i][j]-'a']==-1) { gt[pos_gt][query[i][j]-'a']=++stateNum; pos_gt=stateNum; } else pos_gt=gt[pos_gt][query[i][j]-'a']; if(stateNum==maxStateNum) { maxStateNum*=2; int** tmp=(int**)malloc(sizeof(int*)*maxStateNum); for(int x=0;x<maxStateNum;++x) tmp[x]=(int*)malloc(sizeof(int)*26); for(int x=0;x<stateNum;++x) { for(int y=0;y<26;++y) tmp[x][y]=gt[x][y]; free(gt[x]); } free(gt); for(int x=stateNum;x<maxStateNum;++x) for(int y=0;y<26;++y) tmp[x][y]=-1; gt=tmp; int* ot=(int*)malloc(sizeof(int)*maxStateNum); for(int i=0;i<stateNum;++i) ot[i]=output[i]; for(int i=stateNum;i<maxStateNum;++i) ot[i]=-1; free(output); output=ot; } } output[pos_gt]=0; map[i]=pos_gt; } for(int i=0;i<26;++i) if(gt[0][i]==-1) gt[0][i]=0; }
产生goto表,每次有新的模式,从起始状态开始,若存在相应的路径,则变换到该路径的状态,若没有,则创建新的状态,并转到该状态。
void generateFail() { int maxSizeOfQueue=500; list<int> queue; fail[0]=0; for(int i=0;i<26;++i) if(gt[0][i]!=-1&>[0][i]!=0) { queue.push_back(gt[0][i]); fail[gt[0][i]]=0; } while(!queue.empty()) { int currentState=queue.front(); queue.pop_front(); for(int i=0;i<26;++i) if(gt[currentState][i]!=-1&>[currentState][i]!=0) { int st=fail[currentState]; while(gt[st][i]==-1) st=fail[st]; fail[gt[currentState][i]]=gt[st][i]; queue.push_back(gt[currentState][i]); } } }
从0状态开始,0状态不会失败,1状态失败总是到0。然后层次遍历,对于fail[r],查看他的前一个状态p,p和r之间有‘a’边,若fail[p]存在‘a’的边,则fail[r]=goto(fail[p],a)。若没有,则检查fail[fail[p]],直到存在.0状态不会失败,确保迭代终止。
void parse()
{
int pos_gt=0;
for(int i=0;t[i]!='\0';++i)
{
while(gt[pos_gt][t[i]-'a']==-1)
pos_gt=fail[pos_gt];
pos_gt=gt[pos_gt][t[i]-'a'];
int tgt=pos_gt;
while(tgt!=0)
{
if(output[tgt]!=-1)
++output[tgt];
tgt=fail[tgt];
}
}
}
最后遍历主串。
相关文章推荐
- LightOJ 1427 求每个模式串在母串中出现的次数
- LightOJ 1427 -Repository(ac自动机)
- LightOJ 1427 Substring Frequency (II)(AC自动机裸)
- LightOJ 1427 Substring Frequency (II)(ac自动机水题)
- LightOJ 题目1427 - Substring Frequency (II)(AC自动机)
- LightOJ - 1427 - Substring Frequency (II)(AC自动机)
- LightOJ 1427 Substring Frequency (II) (AC自动机)
- lightoj 1427 Substring Frequency (||) (AC自动机)
- lightoj 1427 Substring Frequency (II) (ac自动机)
- lightoj--1155-- Power Transmission (最大流拆点)
- lightOJ 1004 - Monkey Banana Problem
- LightOJ--1094-- Farthest Nodes in a Tree(树的直径裸题)
- lightoj 1018 - Brush (IV)
- LightOJ 1074 O - Extended Traffic(SPFA判断负环)
- LightOJ1316 A Wedding Party(状压DP)
- lightoj1179 - Josephus Problem&&hdoj2211【约瑟夫环】
- lightoj 1422 - Halloween Costumes(区间DP)
- LightOJ 1356 Aladdin and the Flying Carpet(唯一分解定理)
- LightOJ 1031 - Easy Game【区间dp】
- lightOJ 1186 Incredible Chess