UVALive 3942 Remember the Word 前缀树Trie

来源:互联网 发布:电脑插件软件 编辑:程序博客网 时间:2024/06/06 09:34

Remember the Word

给出一个由S个不同单词组成的字典和一个长字符串,把这个字符串分解成若干个单词的连接(单词可以重复使用),有多少种方法

sample input:

abcd

4

a

b

cd

ab

sampsample output
Case 1 : 2


解题思路:

这题为什么会用前缀树来做呢,既然是要找有多少种分解方法,其实关键点还是后面的递推关系来找的

d[i] = (d[i]+d[i+len[p[j]]])%MOD ;
对于原串从位置i开始的分解方法,等于从i开始找到多少个字符串然后i+找到的字符串的长度位置的d[i+len]因为是从后往前找,所以这个位置的值

是已知的,所以最后的d[0]就是本题的解。

那么怎么找字符串?暴力循环肯定会超时,所以这就需要一个非常好的数据结构来帮助我们快速的找到字符串

那就是前缀树了Trie,我们需要它做的就是根据开始位置i往后找出所有的可以分解的单词, 获取他们的长度用于最后的递推。

这样是非常节省时间的

思路就是这些,刚开始会很难想,但是相信这样的题目做多了,会手到擒来的。

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;const int maxnode = 400010 ;const int sigma_size = 26 ;struct Trie{    int ch[maxnode][sigma_size];    int val[maxnode] ;    int sz ;    void clear(){///构造器        sz = 1 ;///节点总数        memset(ch,0,sizeof(ch));///节点矩阵    }    int idx(char c){///字符c的编号        return c-'a' ;    }    void insert(const char *s,int v){        int u = 0 , n = strlen(s);///初始根节点        for(int i=0;i<n;i++){            int c = idx(s[i]);            if(!ch[u][c]){///如果节点不存在                memset(ch[sz],0,sizeof(ch[sz]));///新位置清空                val[sz] = 0 ;///节点的附加值初始为0                ch[u][c] = sz++ ;///赋值,让树连上这个新节点            }            u = ch[u][c] ;///节点往下走        }        val[u] = v ;///节点最后的附加信息代表是字符串编号    }///找字符串s的长度不超过len的前缀void find(const char *s,int len,vector<int>& ans){        int u = 0 ;        for(int i = 0;i<len;i++){            if(s[i]=='\0')break ;            int c = idx(s[i]);            if(!ch[u][c])break ;            u = ch[u][c] ;            if(val[u]!=0)ans.push_back(val[u]);        }    }};const int maxl = 300000 + 10; // 文本串最大长度const int maxw = 4000 + 10;   // 单词最大个数const int maxwl = 100 + 10;   // 每个单词最大长度const int MOD = 20071027;int d[maxl];int len[maxw];int S ;char text[maxl];char word[maxwl];Trie trie ;int main(){    int cas = 1 ;    while(~scanf("%s%d",text,&S)){        trie.clear();        for(int i=1;i<=S;i++){            scanf("%s",word);            len[i] = strlen(word);            trie.insert(word,i);        }        memset(d,0,sizeof(d));        int L = strlen(text);        d[L] = 1 ;        for(int i = L -1 ;i>=0;i--){            vector<int>p;            trie.find(text+i,L-i,p);            for(int j=0;j<p.size();j++){                d[i] = (d[i]+d[i+len[p[j]]])%MOD ;            }        }        printf("Case %d: %d\n", cas++, d[0]);    }    return 0;}



0 0
原创粉丝点击