UVALive - 3942 - Remember the Word (Trie树)

UVALive - 3942

Remember the Word
Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu

Submit Status

Description

Neal is very curious about combinatorial problems, and now here comes a problem about words. Knowing that Ray has a photographic memory and this may not trouble him, Neal gives it to Jiejie.

Since Jiejie can't remember numbers clearly, he just uses sticks to help himself. Allowing for Jiejie's only 20071027 sticks, he can only record the remainders of the numbers divided by total amount of sticks.

The problem is as follows: a word needs to be divided into small pieces in such a way that each piece is from some given set of words. Given a word and the set of words, Jiejie should calculate the number of ways the given word can be divided, using the words in the set.

Input

The input file contains multiple test cases. For each test case: the first line contains the given word whose length is no more than 300 000.

The second line contains an integer S , 1S4000 .

Each of the following S lines contains one word from the set. Each word will be at most 100 characters long. There will be no two identical words and all letters in the words will be lowercase.

There is a blank line between consecutive test cases.

You should proceed to the end of file.

Output

For each test case, output the number, as described above, from the task description modulo 20071027.

Sample Input

abcd 
4 
a 
b 
cd 
ab

Sample Output

Case 1: 2

Source

Regionals 2007 >>  Asia - Nanjing






Tire树,,前几次都是用结构体链表写得,,感觉用二维数组有点理不清,,这次看大白书用了二维数组描述的Trie树


AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define LL long long  
using namespace std; 

const LL maxnode    = 4010 * 100;
const LL sigma_size = 26;
const LL maxlen     = 100;
const LL maxn       = 300010;
const LL MOD        = 20071027;

char s[maxn];
int f[maxn];

struct Trie
{
	int ch[maxnode][sigma_size];
	int val[maxnode];
	int size; 		//结点总数 
	Trie() { 
		size = 1;
		memset(ch[0], 0, sizeof(ch[0]));
		memset(val,0,sizeof(val));
	} 		//初始时只有一个根结点
	void clear(){		//另一种初始化 
         size = 1;
         memset(ch[0],0,sizeof(ch[0]));
         memset(val,0,sizeof(val));
    }
	
	int newnode(int u) {			//创建新结点 
		memset(ch[size], 0, sizeof(ch[size]));
		val[size] = u;				//u为附加信息,这里为u=0,代表不是单词最后一个字母 
		return size++;				//后一个结点 
	} 
	int idx(char c) { return c - 'a'; } 
	
	//插入字符串s,附加信息为v,v必须非0,因为0代表“本结点不是单词结点” 
	void insert(char *s) {
		int u = 0, n = strlen(s);
		for(int i = 0; i < n; i++) {
			int c = idx(s[i]);
			if(!ch[u][c]) ch[u][c] = newnode(0);//结点不存在,创建新结点 
			u = ch[u][c];						//往后走 
		}
		val[u] = 1;//val[u] = v; 字符串的最后一个字符的附加信息为v,v为1表示这里是单词最后一个字母 
	} 
	
	void find(int i, char *s) {
		int u = 0, len = 0;
		for(; *s; s++) {
			int c = idx(*s);
			if(ch[u][c]) {
				len++;
				u = ch[u][c];
                f[i+len] = (val[u] * f[i] + f[i + len]) % MOD;
                //递推法:f[i]表示从字符i开始的字符串(即后缀S[i..L])的分解方案数。 
			}
			else break;
 		}
	}
};

Trie *trie;			//这里也可以这样(Trie trie;)下面注释括号里的内容为与此处同时修改的内容 

int main()
{
	int cas = 1;
	while(scanf("%s", &s) != EOF){
		int n, len = strlen(s);
		memset(f, 0, sizeof(f));
		f[0] = 1;
		trie = new Trie();			//初始时,要赋值给指针 ,( tire.clear(); ) 
		
		scanf("%d", &n);
		for(int i=0; i<n; i++){
			char tmp[110];
			scanf("%s", tmp);
			trie->insert(tmp);//调用插入函数,注意这里trie是指针 ( trie.insert(tmp); ) 
		}
		
		for(int i=1; i<=len; i++)
			trie->find(i-1, s+i-1);	//调用查找函数      ( trie.find(i-1, s+i-1);) 
			
		printf("Case %d: %d\n",	 cas++, f[len]);
	}
	return 0;
}











你可能感兴趣的:(二维数组,ACM,uva,trie)