LA3942 Remember the Word

题目链接:https://vjudge.net/problem/UVALive-3942

本篇是刘汝佳《算法竞赛入门经典——训练指南》的读书笔记(复述),详见原书 \(P209\) .

解题思路:

  先用字典树维护字典中所有的单词。

  定义 \(f(x)\) 为以长字符串中第 \(x\) 个字符开始的字符串的分解方案数,则 \(f(x) = sum{f(x+len(i))}\) ,其中 \(i\) 是该字符串的所有前缀。

  用一种类似 \(DFS\) 的方式解决这个问题。

  注意:书中的模数写错了。

AC代码:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 const ll mod = 20071027;
 6 const int maxn = 300000+5;
 7 char inp[maxn];
 8 struct Trie{
 9     int ch[400010][30];
10     int val[400010];
11     int sz;
12     void inserts(char *s,int v){
13         int u=0,n=strlen(s);
14         for(int i=0;i<n;i++){
15             int c=s[i]-'a';
16             if(!ch[u][c]){
17                 memset(ch[sz],0,sizeof(ch[sz]));
18                 val[sz]=0;
19                 ch[u][c]=sz++;
20             }
21             u=ch[u][c];
22         }
23         val[u]=v;
24     }
25 };
26 Trie tree;
27 ll f[maxn];
28 
29 ll solve(int head,int tail){
30     if(f[head]!=-1) return f[head];
31     int now=0;
32     ll ret=0;
33     for(int i=head;i<tail;i++){
34         int c=inp[i]-'a';
35         int Next=tree.ch[now][c];
36         if(Next==0){
37             f[head]=ret;
38             return ret;
39         }
40         if(tree.val[Next])
41             ret=(ret+solve(i+1,tail))%mod;
42         now=Next;
43     }
44     f[head]=ret;
45     return ret;
46 }
47 int main(){
48     char word[110];
49     int kase=1;
50     while(scanf("%s",inp)==1){
51         int S;
52         memset(f,-1,sizeof(f));
53         tree.sz=1;
54         memset(tree.ch[0],0,sizeof(tree.ch[0]));
55         scanf("%d",&S);
56         while(S--){
57             scanf("%s",word);
58             tree.inserts(word,1);
59         }
60         int tail=strlen(inp);
61         f[tail]=1;
62         printf("Case %d: %lld\n",kase++,solve(0,tail));
63     }
64     return 0;
65 }

 

转载于:https://www.cnblogs.com/Blogggggg/p/8545301.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值