Uva 1401 - Remember the Word//TRie

   这道题目主用递推做。

   设一个单词W,由(w1,w2,···,wn)个字母组成,判断其有多少种单词的组合方法。

   给定任意一个后缀(wi,wi+1,···,wn),想要判断有多少种组合方法,就要找到它的前缀。不妨设(wi,wi+1,···,wn)这个后缀的前缀为x,就要找到这个后缀有多少个前缀(这里所说的前缀是说的是单词)。不妨设d(i)表示从i到n这个后缀有多少种组合方法,设x为这个后缀种的前缀,剩下的那部分字符串为y。那么d(i) = d(len(x)+i)。

    为什么呢?一个前缀至少对应一种组合,但是这个组前缀不一定是符合的,需要判断y是不是单词。因此还需要判断d(len(x)+i)有多少种组合。因为一个后缀中有多个前缀,所以要对所有的前缀求和。即有下面的递推关系式:

   d(i) = sum{d(len(x)+i)}

   所以用Trie树可以快速的找出前缀。

   下面是代码:

#include<stdio.h>
#include<string.h>
#define maxn 500010

int ch[maxn][26];
int val[maxn],cnt,n;
int d[maxn];
char str[maxn],s[110];

void initi()
{
    cnt = 1;
    memset(ch[0],0,sizeof(ch[0]));
    memset(d,0,sizeof(d));
}

void insert_Trie(char *s)
{
    int u = 0;
    while(*s)
    {
        int id = *s - 'a';
        if(ch[u][id] == 0)
        {
            memset(ch[cnt],0,sizeof(ch[cnt]));
            val[cnt] = 0;
            ch[u][id] = cnt++;
        }
        u = ch[u][id];
        s++;
    }
    val[u] = -1;
}

int main()
{
    int c = 0;
    while(scanf("%s",str) != EOF)
    {
        c++;
        initi();
        scanf("%d",&n);
        for(int i = 0; i < n; i++)
        {
            scanf("%s",s);
            insert_Trie(s);
        }
        int len = strlen(str);
        d[len] = 1;
        for(int i = len-1; i >= 0; i--)
        {
            int j,k;
            int u = 0;
            for(j = 0,k = i; k < len; j++,k++)
            {
                int id = str[k] - 'a';
                if(!ch[u][id]) break;
                else if(val[ch[u][id]] == -1)
                {
                    d[i] += d[i+j+1];
                    if(d[i] >= 20071027) d[i] %= 20071027;
                }
                u = ch[u][id];
            }
        }
        printf("Case %d: ",c);
        printf("%d\n",d[0]%20071027);
    }
    return 0;
}

注:

    一、当找前缀时不用query操作

    二、结果很大,int会爆,需要处理一下,因为是mod。

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值