LA 3942(Remember the Word-Trie)[Template:Trie]

3942 - Remember the Word

Time limit: 3.000 seconds

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

可以用Trie存字符串,dp

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (20071027)
#define MAXNode (100000*5+10)
#define Sigma_size (26)
#define MAXN (4000+10)
#define MAXLen (300000+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
class Trie
{
public:
	int ch[MAXNode][Sigma_size];
	int v[MAXNode],siz;
	Trie(int _siz=0):siz(_siz){MEM(ch) MEM(v)}
	void mem(int _siz=0){siz=_siz; MEM(ch) MEM(v)	}
	int idx(char c){return c-'a';}
	void insert(char *s,int val=0)
	{
		int u=0,n=strlen(s);
		Rep(i,n)
		{
			int c=idx(s[i]);
			if (!ch[u][c])
			{
				++siz;
				MEM(ch[siz]);
				ch[u][c]=siz;
			}
			u=ch[u][c];
		}
		v[u]=val;
	}
	void find(char *s,ll *x)
	{
		int u=0,n=strlen(s);
		Rep(i,n)
		{
			int c=idx(s[i]);
			if (!ch[u][c])
			{
				return;
			}
			u=ch[u][c];

			if (v[u]) upd(*x,*(x+i+1));
		}
	}

}T;
char s[MAXLen],t[MAXN];
int n;
ll d[MAXLen];
int main()
{
//	freopen("la3942.in","r",stdin);
//	freopen(".out","w",stdout);

	int tt=1;
	while(scanf("%s",s)==1)
	{
		int len=strlen(s);
		scanf("%d",&n);
		T.mem(0);
		For(i,n)
		{
			scanf("%s",t);
			T.insert(t,1);
		}
		MEM(d) d[len]=1;
		RepD(i,len-1)
		{
			T.find(s+i,d+i);
		}
	//	Rep(i,len) cout<<d[i]<<' ';
		printf("Case %d: %d\n",tt++,d[0]);
	}

	return 0;
}
时间: 2024-11-05 02:03:52

LA 3942(Remember the Word-Trie)[Template:Trie]的相关文章

LA 3942 Remember the Word (Trie)

Remember the Word 题目:链接 题意:给出一个有S个不同单词组成的字典和一个长字符串.把这个字符串分解成若干个单词的连接(单词可以重复使用),有多少种方法? 思路:令d[i]表示从字符i开始的字符串(后缀s[i..L])的分解数,这d[i] = sum{d(i+len(x)) | 单词x是其前缀}.然后将所有单词建成一个Trie树,就可以将搜索单词的复杂度降低. 代码: #include<map> #include<set> #include<queue>

LA ——3942 - Remember the Word(Trie 入门)

3942 - Remember the Word Regionals 2007 >> Asia - Nanjing Time limit: 3.000 seconds ------------------------------------------------------ 从右往左地推,令dp[i] 表示字符串  S[i....len]的分解方案数,则dp[i]=sum(dp[i+len(x)])  ,我们只要枚举 S[i....len]的前缀,在所给的单词中查找前缀,如果存在,则进行状态

单词拆解&amp;前缀树&amp;树上DP LA 3942 Remember the Word

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=505&page=show_problem&problem=4147 3942 - Remember the Word Neal is very curious about combinatorial problems, and now here comes a problem about words. Knowing

LA 3942 Remember the Word

已知一些单词,选择其中一些单词组成目的字符串,问共有多少种方法.其实初看到这道题,自然而然地可以想到动态规划中经典的硬币问题:例如,问1元,2元,5元,总共有多少种方法能组成20元?这里不过是把硬币换成了单词而已.但是,如果真的只是像硬币问题一样每个单词都轮询一遍,显然太慢了,最多要有300000*4000*100次比对. 假如利用trie数的话,至多只要比对100次,就能找到所有匹配的单词.然后将字符串从左至右DP即可.设d[i]表示从位置i开始的后缀的解,已知d[i]~d[n],那么求d[i

LA 3942 Remember the Word (Trie树)

——刘汝佳的白皮书里面介绍的题目. /* Problem: Status : By WF, */ #include "algorithm" #include "iostream" #include "cstring" #include "cstdio" #include "string" #include "stack" #include "cmath" #inclu

LA 3942 - Remember the Word (字典树 + dp)

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1943 题目大意: 给定一个字符串和给定一个单词集合.问从给定单词集合中选取单词,有多少种选取方法刚好拼接成字符串. 例如: abcd 4 a b cd ab 有两种 a-b-cd ab-cd 这两种情况 解题思路: 因为给定的字符串的长度是3*10^5所以暴力就不能解决问题了

LA 3942 Remember the Word(字典树+DP)

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1943 题意:一个长字符串和多个短字符串,求短字符串有多少种方式组成长字符串. 状态转移方程: dp[i] = sum(d[i + len(x)])  (x是s[i...L]的前缀) 对于每个i,如果直接暴力寻找s[i...L]的前缀,复杂度为O(nm) (n为短字符

LA 3942 Remember the Word 字典树+dp

#include <cstdio> #include <cstring> using namespace std; #define mod 20071027 int dic[401000][28],val[401000]; char str[301000]; int dp[301000]; int s,sz; char T[110]; void insert(char *ch) { int u=0,len=strlen(ch); for(int i=0;i<len;i++)

UVALive 3942 - Remember the Word(DP,数组Trie+指针Trie)

UVALive 3942 - Remember the Word(DP,数组Trie+指针Trie) ACM 题目地址: UVALive 3942 - Remember the Word 题意: 给一些单词,然后给一个长的单词,问有几种方法能组成这个大单词,单词可以重复用. 分析: DP[i]=sum{DP[j} (i<j<len),从后往前求. 本来用数组Trie写得爽爽的,1A了. 发现2s多,不能忍! 然后用指针Trie写了一遍,各种出错,整个人都不好了... 研究了一遍别人代码,发现快