【字符串·Trie】uva3942 Remember the words

来源:互联网 发布:淘宝联盟网页版怎么用 编辑:程序博客网 时间:2024/05/19 20:43

遇到多校第五场,1002,于是开始学trie树和AC自动机;
模板用的挑程,Trie树用一个二维数组ch[节点数目][字符种类数]实现; ch[I][j]表示第i个节点伸向j字符,如果存在字符j接在节点i之后,则ch[I][j]>0;

在trie上插入“ba”“bcd”的例子

首先一道模板题uva3942
用d[I]表示 后缀I-L的分解方案数
d[I] = sum{d[I+len(x)]} 其中len(x) 是合法单词且是I-L的前缀;
以上抄的刘汝佳orz

我的理解是,从某个点i开始(包括i)某个前缀刚好是单词,就可以把单词结尾处的d[结尾点]加到d[I]上;

#define _CRT_SECURE_NO_WARNINGS#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;typedef long long ll;const int maxn = 300010;const int mod = 20071027;//建树int ch[maxn][26];int val[maxn];int sz;void init(){ sz = 1; memset(ch[0], 0, sizeof(ch[0])); }int idx(char c){ return c - 'a'; }int d[maxn];char t[maxn];void insert(char *s){    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;            ch[u][c] = sz++;        }        u = ch[u][c];    }    val[u] = 1;}void query(int id,char *s){    d[id] = 0;    int u = 0;    for (int i = id; s[i]; i++){        int c = idx(s[i]);        if (!ch[u][c]) return;        u = ch[u][c];        //如果是单词节点        if (val[u]) d[id] = (d[id] + d[i + 1]) % mod;    }}int n;void solve(char *s){    int len = strlen(s);    d[len] = 1;    //从后向前计算d[I];    for (int i = len - 1; i >= 0; i--){        query(i, s);    }}char s[110];int main(){    int kase = 0;    while (~scanf("%s", t)){        init();        scanf("%d", &n);        for (int i = 1;i<=n;i++){            scanf("%s", s);            insert(s);        }        solve(t);        printf("Case %d: %d\n", ++kase,d[0]);    }}
原创粉丝点击