发现字典里面的单词数目多且长度短,可以用字典树保存
f[i]表示s[i~L]的分割方式,则有f[i]=∑f[i+len(word[j])] 其中word[j]为s[i~L]的前缀
注意字典树又叫前缀树,所以用前缀更方便,否则按顺序dp的话就要把字符倒序了
复杂度O(L*l) L为字符串长度,l为单词长度
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define MAXN 300005 #define MOD 20071027 using namespace std; struct Trie{ Trie* nxt[26]; int v; Trie(){ for(int i=0;i<26;i++){ nxt[i]=NULL; } v=0; } }; Trie *root; void insert(char s[],int vl){ Trie *p=root; int len=strlen(s); for(int i=0;i<len;i++){ int t=s[i]-97; if(p->nxt[t]){ p=p->nxt[t]; } else{ p->nxt[t]=new Trie; p=p->nxt[t]; } } p->v=vl; } int f[MAXN]; char s[MAXN]; int n,L; int find(int st){ int ret=0; Trie *p=root; for(int i=st;i<L;i++){ int t=s[i]-97; if(p->nxt[t]){ p=p->nxt[t]; if(p->v){ (ret+=f[i+1])%=MOD; } } else{ return ret; } } return ret; } void del(Trie *p){ if(p){ for(int i=0;i<26;i++){ if(p->nxt[i]){ del(p->nxt[i]); } } delete p; } } int main() { int T=0; while(~scanf("%s",s)){ memset(f,0,sizeof(f)); del(root); L=strlen(s); root=new Trie; scanf("%d",&n); for(int i=1;i<=n;i++){ char ch[105]={0}; scanf("%s",ch); insert(ch,1); } f[L]=1; for(int i=L-1;i>=0;i--){ f[i]=find(i); } printf("Case %d: %d ",++T,f[0]); } return 0; }