[Trie树][dp] LA3942 Remember the Word 真·解法

来源:互联网 发布:开淘宝网店的流程 编辑:程序博客网 时间:2024/05/29 11:42

在上一篇的解法中,我们使用Trie树优化的dp,复杂度达到3e9,限时3s,奇迹般地跑了2.929sAC了。然鹅。。。这并不是使用Trie的正确姿势。
Trie树是从根节点向下查找,如果我们计算的顺序和它一致,会大大降低复杂度。
重新定义dpi为字符串s的后缀i(即sislen)的拆分方法。
则,

dpi=s[i,j]Triedpj+1

这样对于dpij可以按从ilen的顺序,在Trie中便可逐层向下查找,时间复杂度下降到O(nl),这次0.072s就过啦~~~

#include<bits/stdc++.h>typedef long long LL;typedef unsigned long long ull;using namespace std;const int maxn = 3e5+5;const int maxn2 = 400000+8;const int maxm = 26;const int maxn3 = 105;const int M = 20071027;char s[maxn], s2[maxn3];struct Trie{    int ch[maxn2][maxm];    bitset<maxn2> val;    int tot = 1;    void init()    {        memset(ch[0], 0, sizeof ch[0]);        val.reset();        tot = 1;    }    void add(char *s)    {        int n = strlen(s);        int cur = 0, id;        for(int i = 0; i < n; ++i)        {            id = s[i] - 'a';            if(!ch[cur][id])            {                memset(ch[tot], 0, sizeof ch[tot]);                ch[cur][id] = tot++;            }            cur = ch[cur][id];        }        val[cur] = 1;    }    bool finda(char *s)    {        int n = strlen(s);        int cur = 0, id;        for(int i = 0; i < n; ++i)        {            id = s[i] - 'a';            if(!ch[cur][id]) return false;            cur = ch[cur][id];        }        return val.test(cur);    }}tr;LL dp[maxn];int main(){    int Case = 1;    while(~scanf("%s", s+1))    {        int n;        cin >> n;        int len = strlen(s+1);        tr.init();        for(int i = 0; i < n; ++i)        {            scanf("%s", s2);            tr.add(s2);        }        memset(dp, 0, sizeof dp);        dp[len + 1] = 1;        for(int i = len; i >= 1; --i)        {            int cur = 0, id;            for(int j = i; j <= len; ++j)            {                id = s[j] - 'a';                if(!tr.ch[cur][id]) break;                cur = tr.ch[cur][id];                if(tr.val[cur]) dp[i] = (dp[i] + dp[j+1])%M;            }        }        printf("Case %d: ", Case++);        cout << dp[1] << endl;    }    return 0;}