LA3942 Remember the Word(Trie+DP)

来源:互联网 发布:联通 套餐 4g数据副卡 编辑:程序博客网 时间:2024/09/21 06:18

题意:给出一个字符串(长度最长为300000)和n个单词,n不会超过4000,单词长度不会超过100,求字符串能由n个单词构成的个数,如果个数超过20071027,就对其求模

思路:先用n个单词构成Trie,d(i)=sum(d(i+len(x)),其中x是s[i..L]的前缀

在用dp时,先有记忆化的递归,但是当字符串长度为最长时,而单词长度比较短,而又能够构成字符串。例如如果字符串由300000个b组成,单词有2个,分别为b和bb,在用递归时,可能造成栈超过其深度限制。

具体代码如下:(这段代码可能会造成栈深度过深,抛出异常)

#include <iostream>#include <cstring>#include <string>#include <cstdio>using namespace std;const int N = 400010;const int MAX_CHILD_NUM = 26;const int WORD_LEN = 110;const int MOD = 20071027;int ch[N][MAX_CHILD_NUM];int val[N];int cnt;int dp[N];class Trie{public:    void init()    {        memset(ch, 0x00, sizeof(ch));        memset(val, 0x00, sizeof(val));        memset(dp, 0xff, sizeof(dp));        cnt = 0;    }    void insert(string s)    {        int u = 0;        for (int i = 0; i < s.length(); i++)        {            int idx = s[i] - 'a';            if (!ch[u][idx])            {                cnt++;                ch[u][idx] = cnt;                val[cnt] = 0;            }            u = ch[u][idx];        }        val[u] = 1;    }    int find(string s)    {        int u = 0;        int len = s.length();        int& ans = dp[len] ;        if (len == 0)        {            return ans = 1;        }        if (ans >= 0) return ans;        ans = 0;        for (int i = 0; i < len; i++)        {            int idx = s[i] - 'a';            u = ch[u][idx];            if (u == 0) break;            if (val[u])            {                ans += find(s.substr(i + 1));                ans %= MOD;            }        }        return ans;    }};char buf[N], tmp[WORD_LEN];Trie trie;int main(){#ifndef ONLINE_JUDGE    freopen("d:\\program\\clion\\spoj.txt", "r", stdin);#endif    string s;    int cas = 1;    while (scanf("%s", buf) == 1)    {        trie.init();        int n;        scanf("%d", &n);        for (int i = 0; i < n; i++)        {            string word;            scanf("%s", tmp);            word = tmp;            trie.insert(word);        }        s = buf;        int ans = trie.find(s);        printf("Case %d: %d\n", cas++, ans);    }    return 0;}

换成dp的递推式后,在用函数实现时,将字符串string作为参数超时,换成引用 后accepted,因为字符串比较长时,涉及到大量的复制,用引用就不会

代码如下:

#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <exception>using namespace std;const int N = 400010;const int MAX_CHILD_NUM = 26;const int WORD_LEN = 110;const int MOD = 20071027;int ch[N][MAX_CHILD_NUM];int val[N];int cnt;int dp[N];class Trie{public:    void init()    {        memset(ch, 0x00, sizeof(ch));        memset(val, 0x00, sizeof(val));        memset(dp, 0xff, sizeof(dp));        cnt = 0;    }    void insert(string s)    {        int u = 0;        for (int i = 0; i < s.length(); i++)        {            int idx = s[i] - 'a';            if (!ch[u][idx])            {                cnt++;                ch[u][idx] = cnt;                val[cnt] = 0;            }            u = ch[u][idx];        }        val[u] = 1;    }    int find(string& s)    {        int len = s.length();        for (int i = 0; i <= len; i++)        {            cal(s, len - i);        }        return dp[0];    }private:    void cal(string& s, int start)    {        int u = 0;        int len = s.length();        int& ans = dp[start];        if (start == len)        {            ans = 1;            return;        }        ans = 0;        for (int i = start; i < len; i++)        {            int idx = s[i] - 'a';            u = ch[u][idx];            if (u == 0) break;            if (val[u])            {                ans += dp[i + 1];                ans %= MOD;            }        }    }};char buf[N], tmp[WORD_LEN];Trie trie;int main(){#ifndef ONLINE_JUDGE    freopen("d:\\program\\clion\\spoj.txt", "r", stdin);#endif    string s;    int cas = 1;    while (scanf("%s", buf) == 1)    {        trie.init();        int n;        scanf("%d", &n);        for (int i = 0; i < n; i++)        {            string word;            scanf("%s", tmp);            word = tmp;            trie.insert(word);        }        s = buf;        int ans = trie.find(s);        printf("Case %d: %d\n", cas++, ans);    }    return 0;}


将变量封装到类中,代码如下:

#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <exception>using namespace std;const int N = 400010;const int MAX_CHILD_NUM = 26;const int WORD_LEN = 110;const int MOD = 20071027;class Trie{public:    void init()    {        memset(ch, 0x00, sizeof(ch));        memset(val, 0x00, sizeof(val));        memset(dp, 0xff, sizeof(dp));        cnt = 0;    }    void insert(string s)    {        int u = 0;        for (int i = 0; i < s.length(); i++)        {            int idx = s[i] - 'a';            if (!ch[u][idx])            {                cnt++;                ch[u][idx] = cnt;                val[cnt] = 0;            }            u = ch[u][idx];        }        val[u] = 1;    }    int find(string& s)    {        int len = s.length();        for (int i = 0; i <= len; i++)        {            cal(s, len - i);        }        return dp[0];    }private:    void cal(string& s, int start)    {        int u = 0;        int len = s.length();        int& ans = dp[start];        if (start == len)        {            ans = 1;            return;        }        ans = 0;        for (int i = start; i < len; i++)        {            int idx = s[i] - 'a';            u = ch[u][idx];            if (u == 0) break;            if (val[u])            {                ans += dp[i + 1];                ans %= MOD;            }        }    }private:    int ch[N][MAX_CHILD_NUM];    int val[N];    int cnt;    int dp[N];};char buf[N], tmp[WORD_LEN];Trie trie;int main(){#ifndef ONLINE_JUDGE    freopen("d:\\program\\clion\\spoj.txt", "r", stdin);#endif    string s;    int cas = 1;    while (scanf("%s", buf) == 1)    {        trie.init();        int n;        scanf("%d", &n);        for (int i = 0; i < n; i++)        {            string word;            scanf("%s", tmp);            word = tmp;            trie.insert(word);        }        s = buf;        int ans = trie.find(s);        printf("Case %d: %d\n", cas++, ans);    }    return 0;}



0 0
原创粉丝点击