Remember the Word
DescriptionNeal 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, 1 ≤ S ≤ 4000. 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
题意:给你一个长字符串,和一些短字符串,问你用短字符串拼成长字符串的方案数
分析:很明显的dp题。定义状态dp[i]表示从i开始的字符串(后缀)的方案数,则转移方程就是dp[i]+=dp[i+len(x)],x是从i开始的字符串的前缀。
接下来只要求出所有的前缀的长度就行了,枚举肯定会超时,考虑用字典树来做,将短的字符串按字典树建树,单词节点保存单词的长度和是否为单词的标记,每次去查找就行了。
#include<bits/stdc++.h> using namespace std; const int MAXN = 26; const int MOD = 20071027; typedef struct Trie_Node { bool isWord; int len; struct Trie_Node *next[MAXN]; }Trie; int l[110],tot; void Trie_insert(Trie *root,char *str) { Trie *p=root; int len=strlen(str); for(int i=0;i<len;i++) { int k=str[i]-‘a‘; if(p->next[k]==NULL) { Trie *t=new Trie; for(int j=0;j<MAXN;j++) t->next[j]=NULL; t->isWord=false; p->next[k]=t; } p=p->next[k]; } p->isWord=true; p->len=len; } int Trie_search(Trie *root,char *str) { Trie *p=root; int len=strlen(str); for(int i=0;i<len;i++) { int k=str[i]-‘a‘; if(p->next[k]==NULL) return tot; if(p->next[k]->isWord) { tot++; l[tot]=p->next[k]->len; } p=p->next[k]; } return tot; } void Trie_del(Trie *root) { for(int i=0;i<MAXN;i++) { if(root->next[i]!=NULL) Trie_del(root->next[i]); } free(root); } char str[300010]; char ss[110]; int dp[3000010]; int main() { int n; int iCase=0; while(scanf("%s",str)!=EOF) { iCase++; //cout<<str<<endl; scanf("%d",&n); memset(dp,0,sizeof(dp)); Trie *root=new Trie; for(int i=0;i<MAXN;i++) root->next[i]=NULL; root->isWord=false; for(int i=1;i<=n;i++) { scanf("%s",ss); //cout<<ss<<endl; Trie_insert(root,ss); } int len=strlen(str); dp[len]=1; for(int i=len-1;i>=0;i--) { tot=0; memset(l,0,sizeof(l)); //cout<<str+i<<endl; Trie_search(root,str+i); for(int j=1;j<=tot;j++) { dp[i]+=dp[i+l[j]]; dp[i]%=MOD; } } printf("Case %d: %d\n",iCase,dp[0]); Trie_del(root); } return 0; }