lightoj-1427:Substring Frequency

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.

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.

Sample Input

Output for Sample Input

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



剛開始沒看題目,用kmp做,超時,後來看了一下主題,知道要用AC算法。
#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];
		}
	}
}

最後遍歷主串。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章