uva 1401 拼单词

题目描述

  • Neal 对有关组合的问题很感兴趣,现在他有一个关于单词的有趣问题要解决:

  • 他知道大佬Ray的记忆力像存储器一样好,这样的问题肯定难不倒他,于是Neal把问题给了蒟蒻Jiejie。Jiejie经常记不住数字,他就用火柴棒来帮助自己记忆。Jiejie最多只能用20071027根火柴棒(因为他只有那么多),所以Jiejie数出来的数量需要关于20071027取模

  • 问题如下: 一个长单词需要被分割成几个小单词(当然小单词都在字典当中)。比如有包含4个单词的字典:{a, b, cd, ab},则长单词abcd有两种分解方法: a+b+cd和ab+cd。

  • 现给定一个由s个不同单词组成的字典和一个长字符串,Jiejie需要把这个长字符串按字典分解成若干个单词,问有多少种分解方法

输入

  • 每个输入文件中有多组测试数据,对于每组测试数据:

  • 第一行是长单词,单词的长度不会超过300,000

  • 第二行是整数s,1≤s≤4000。

  • 接下来的s行,每行是字典中的一个单词,每个单词长度不超过100,所有单词字母都是小写的,且不会有相同单词

  • 每组测试数据间都会有一个空行

  • 你的程序必须处理到文件结束(即EOF)为止

  • 输出
    对于每组测试数据,输出总数对20071027取模后的值,格式参考样例。
    样例输入
    abcd
    4
    a
    b
    cd
    ab
    样例输出
    Case 1: 2

    分析:

            我们令d[i]=x表示S串的后缀[i,L-1]串有多少种构成方式(注意:如果令d[i]=x表示S串的前缀串[0,i]有多少种构成方式的话,就不能用字典树来查找单词了)。其中L=strlen(S),字符从0到L-1下标。

            那么d[i]=sum(  d[i+len(x)]  ) 仅当[i,i+len(x)-1]区间的字符正好是字典中的一个单词时.(想想是不是?)

            然后初值d[L]=1,其他所有d值初始为0,然后从L-1一直递推到0,最终结果就是d[0].

    当我们递推d[i]的时候,我们先用串[i,L-1]去查询字典树,如果查询到了一个长5的单词,那说明d[i] += d[i+5],如果查询到另一个长8的单词,那说明d[i] +=d[i+8].

            另外要说明的是:字典树中的v值保存的是该节点单词的长度,如果该节点不是单词,那么v=0.
     

    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define MAX 26
    const int maxnode=4000*100+100;
    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));//ch值为0表示没有儿子
        }
        int idx(char c)
        {
            return c-'a';
        }
        void insert(char *s)
        {
            int u=0,n=strlen(s);
            for(int i=0;i<n;i++)
            {
                int id=idx(s[i]);
                if(ch[u][id]==0)//无该儿子
                {
                    ch[u][id]=sz;
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz++]=0;
                }
                u=ch[u][id];
            }
            val[u]=n;
        }
        void find(char *s,int len,vector<int> &vc)
        {
            int u=0;
            for(int i=0;i<len;i++)
            {
                int id=idx(s[i]);
                if(ch[u][id]==0)
                    return;
                u=ch[u][id];
                if(val[u]) vc.push_back(val[u]);
            }
        }
    };
     
    Trie trie;
    const int MAXN=300000+1000;
    const int MOD = 20071027;
    int d[MAXN];
    char S[MAXN],word[1000];
    int main()
    {
        int kase=1;
        while(scanf("%s",S)==1)
        {
            int w;
            scanf("%d",&w);
            trie.clear();
            for(int i=0;i<w;i++)
            {
                scanf("%s",word);
                trie.insert(word);
            }
            memset(d,0,sizeof(d));
            int L=strlen(S);
            d[L]=1;
            for(int i=L-1;i>=0;i--)
            {
                vector<int> vc;
                trie.find(S+i,L-i,vc);
                for(int j=0;j<vc.size();j++)
                    d[i]=(d[i]+d[i+vc[j]])%MOD;
            }
            printf("Case %d: %d\n", kase++, d[0]);
        }
        return 0;
    }
     

猜你喜欢

转载自blog.csdn.net/qq_40859951/article/details/84201179
今日推荐