UVALive - 3942:Remember the Word

发现字典里面的单词数目多且长度短,可以用字典树保存

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\n",++T,f[0]);
    }
    return 0;
}

 

posted @ 2017-11-26 12:22  white_hat_hacker  阅读(142)  评论(0编辑  收藏  举报