LA 3942 字典树+递推

本文介绍了一种利用Trie树和动态规划解决字符串分解问题的方法。通过将字典中的单词存储到Trie树中,并使用DP算法计算目标字符串的分解方案数。详细展示了算法的具体实现过程,包括初始化Trie树、插入单词、查找匹配子串等关键步骤。

题目链接

题意:给你s(s <= 4000)个不同单词组成的字典和一个字符串str(len <= 300000),str能分解若干个单词,问有几种分法(单词可以重复使用)。

思路: 把s个单词存入trie里,(str从1开始)用dp[i]表示str的子串(1-i)有几种分法。

从i+1开始在trie里找插入的单词,更新之后的dp。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
#define maxn 300005
const int mod = 20071027;
int dp[maxn];
char str[maxn];
struct trie {
	int tot, c[500005][26];
	int v[500005];
	void init() {
		tot = 0;
		new_node();
	}
	int new_node() {
		memset(c[tot], -1, sizeof(c[tot]));
		v[tot] = 0;
		return tot++;
	}
	void insert(char *s) {
		int u = 0, i, k;
		for(i = 0; s[i]; i++) {
			k = s[i] - 'a';
			if(c[u][k] == -1) c[u][k] = new_node();
			u = c[u][k];
		}
		v[u]++;
	}
	void find(char *s, int j) { //从str的j位置开始在trie中找串
		int u = 0, i, k;
		for(i = j; s[i]; i++) {
			k = s[i] - 'a';
			if(c[u][k] == -1) return;
			u = c[u][k];
			if(v[u]) {
			    dp[i] += dp[j-1] * v[u];
			    if(dp[i] >= mod) dp[i] -= mod;
			}
		}
	}
}a;
int main() {
	int i, j, cas = 1, n;
	char s[105]; 
	while( ~scanf("%s", str+1)) {
		a.init();
		scanf("%d", &n);
		while(n--) {
			scanf("%s", s);
			a.insert(s);
		}
		int len = strlen(str+1);
		memset(dp, 0, sizeof(int)*(len+1)); 
		dp[0] = 1;
		for(i = 1; i <= len; i++) a.find(str, i);
		printf("Case %d: %d\n", cas++, dp[len]);
	}
	return 0;
}


### 什么是递推树及其绘制方法 递推树是一种用于可视化递归过程的工具,能够帮助开发者更直观地理解递归算法的工作原理以及时间复杂度分析。以下是关于递推树绘制的相关说明: #### 定义与作用 递推树(Recursion Tree)是将递归过程中每一层分解的小问题绘制成图形的一种方式[^2]。通过这种树状结构,可以清晰看到每次递归调用所涉及的操作量和数据规模变化。 #### 绘制步骤概述 虽然不允许使用诸如“首先”这样的引导词,但仍可以通过描述各部分逻辑关系来阐述具体做法: - **节点含义**:每一个节点代表一次函数调用的结果或者子问题大小。 - **分支规则**:依据当前层次上的分割策略决定下一层有多少个孩子节点;对于像归并排序这类操作,则会均匀分成两个相等问题。 - **终止条件**:当到达基本情形(base case),即不能再进一步划分时停止扩展该路径下的新节点。 #### 实际案例 - 归并排序为例 考虑归并排序中的递归树构建情况。假设初始数组长度为n,在理想情况下它会产生一颗高度约为log₂n 的完全平衡二叉树[^1]: ```plaintext Level 0: n (original array size) Level 1: n/2 + n/2 ... Until reaching individual elements at leaf level. ``` 每层总工作量保持恒定接近于O(n),因为除了最底层外其他所有内部结点加起来正好等于输入序列总数目减去叶子数目再乘以常系数c. #### Python实现简单例子-Turtle库画分形树展示递归概念 下面给出一段利用Python turtle模块模拟创建一棵简单的分形树程序代码片段作为实例演示如何运用循环嵌套配合参数调整从而生成不同形态图案的同时也体现了深层次上隐藏着相同模式重复出现这一特性正是递归本质所在之处[^3]: ```python import turtle as t def draw_fractal_tree(branch_length, angle_degrees): if branch_length > 5: t.forward(branch_length) new_length = branch_length * .7 t.right(angle_degrees) draw_fractal_tree(new_length ,angle_degrees ) t.left( 2* angle_degrees ) draw_fractal_tree(new_length ,angle_degrees ) t.right(angle_degrees) t.backward(branch_length) t.speed('fastest') t.penup() t.goto(0,-200) t.pendown() draw_fractal_tree(100,20) t.done() ``` 此脚本展示了如何基于固定角度旋转方向不断缩短线条长度直至满足特定阈值才结束整个流程。 #### Fibonacci 数列递归版本解释 最后提及一下经典的Fibonacci数列计算场景里边同样存在明显的递归现象,并且其效率低下主要是由于大量冗余运算造成资源浪费问题突出显示出来需要优化解决方案比如采用记忆化技术手段加以改进提高性能表现等方面内容这里不做详尽展开讨论仅提供原始朴素形式供参考学习用途[^4]. ```c++ #include<stdio.h> int fib(int n){ if(n<=1)return n; else return fib(n-1)+fib(n-2); } // Test code omitted for brevity ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值