diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README.md b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README.md
new file mode 100644
index 0000000000000..6fa7adf713e91
--- /dev/null
+++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README.md
@@ -0,0 +1,380 @@
+---
+comments: true
+difficulty: 中等
+edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README.md
+---
+
+
+
+# [3253. Construct String with Minimum Cost (Easy) 🔒](https://leetcode.cn/problems/construct-string-with-minimum-cost-easy)
+
+[English Version](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README_EN.md)
+
+## 题目描述
+
+
+
+
You are given a string target
, an array of strings words
, and an integer array costs
, both arrays of the same length.
+
+Imagine an empty string s
.
+
+You can perform the following operation any number of times (including zero):
+
+
+ - Choose an index
i
in the range [0, words.length - 1]
.
+ - Append
words[i]
to s
.
+ - The cost of operation is
costs[i]
.
+
+
+Return the minimum cost to make s
equal to target
. If it's not possible, return -1.
+
+
+Example 1:
+
+
+
Input: target = "abcdef", words = ["abdef","abc","d","def","ef"], costs = [100,1,1,10,5]
+
+
Output: 7
+
+
Explanation:
+
+
The minimum cost can be achieved by performing the following operations:
+
+
+ - Select index 1 and append
"abc"
to s
at a cost of 1, resulting in s = "abc"
.
+ - Select index 2 and append
"d"
to s
at a cost of 1, resulting in s = "abcd"
.
+ - Select index 4 and append
"ef"
to s
at a cost of 5, resulting in s = "abcdef"
.
+
+
+
+Example 2:
+
+
+
Input: target = "aaaa", words = ["z","zz","zzz"], costs = [1,10,100]
+
+
Output: -1
+
+
Explanation:
+
+
It is impossible to make s
equal to target
, so we return -1.
+
+
+
+Constraints:
+
+
+ 1 <= target.length <= 2000
+ 1 <= words.length == costs.length <= 50
+ 1 <= words[i].length <= target.length
+ target
and words[i]
consist only of lowercase English letters.
+ 1 <= costs[i] <= 105
+
+
+
+
+## 解法
+
+
+
+### 方法一:字典树 + 记忆化搜索
+
+我们首先创建一个字典树 $\textit{trie}$,字典树的每个节点包含一个长度为 $26$ 的数组 $\textit{children}$,数组中的每个元素都是一个指向下一个节点的指针。字典树的每个节点还包含一个 $\textit{cost}$ 变量,表示从根节点到当前节点的最小花费。
+
+我们遍历 $\textit{words}$ 数组,将每个单词插入到字典树中,同时更新每个节点的 $\textit{cost}$ 变量。
+
+接下来,我们定义一个记忆化搜索函数 $\textit{dfs}(i)$,表示从 $\textit{target}[i]$ 开始构造字符串的最小花费。那么答案就是 $\textit{dfs}(0)$。
+
+函数 $\textit{dfs}(i)$ 的计算过程如下:
+
+- 如果 $i \geq \textit{len}(\textit{target})$,表示已经构造完整个字符串,返回 $0$。
+- 否则,我们从 $\textit{trie}$ 的根节点开始,遍历 $\textit{target}[i]$ 开始的所有后缀,找到最小花费,即 $\textit{trie}$ 中的 $\textit{cost}$ 变量,加上 $\textit{dfs}(j+1)$ 的结果,其中 $j$ 是 $\textit{target}[i]$ 开始的后缀的结束位置。
+
+最后,如果 $\textit{dfs}(0) < \textit{inf}$,返回 $\textit{dfs}(0)$,否则返回 $-1$。
+
+时间复杂度 $O(n^2 + L)$,空间复杂度 $O(n + L)$。其中 $n$ 是 $\textit{target}$ 的长度,而 $L$ 是 $\textit{words}$ 数组中所有单词的长度之和。
+
+
+
+#### Python3
+
+```python
+class Trie:
+ def __init__(self):
+ self.children: List[Optional[Trie]] = [None] * 26
+ self.cost = inf
+
+ def insert(self, word: str, cost: int):
+ node = self
+ for c in word:
+ idx = ord(c) - ord("a")
+ if node.children[idx] is None:
+ node.children[idx] = Trie()
+ node = node.children[idx]
+ node.cost = min(node.cost, cost)
+
+
+class Solution:
+ def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
+ @cache
+ def dfs(i: int) -> int:
+ if i >= len(target):
+ return 0
+ ans = inf
+ node = trie
+ for j in range(i, len(target)):
+ idx = ord(target[j]) - ord("a")
+ if node.children[idx] is None:
+ return ans
+ node = node.children[idx]
+ ans = min(ans, node.cost + dfs(j + 1))
+ return ans
+
+ trie = Trie()
+ for word, cost in zip(words, costs):
+ trie.insert(word, cost)
+ ans = dfs(0)
+ return ans if ans < inf else -1
+```
+
+#### Java
+
+```java
+class Trie {
+ public final int inf = 1 << 29;
+ public Trie[] children = new Trie[26];
+ public int cost = inf;
+
+ public void insert(String word, int cost) {
+ Trie node = this;
+ for (char c : word.toCharArray()) {
+ int idx = c - 'a';
+ if (node.children[idx] == null) {
+ node.children[idx] = new Trie();
+ }
+ node = node.children[idx];
+ }
+ node.cost = Math.min(node.cost, cost);
+ }
+}
+
+class Solution {
+ private Trie trie = new Trie();
+ private char[] target;
+ private Integer[] f;
+
+ public int minimumCost(String target, String[] words, int[] costs) {
+ for (int i = 0; i < words.length; ++i) {
+ trie.insert(words[i], costs[i]);
+ }
+ this.target = target.toCharArray();
+ f = new Integer[target.length()];
+ int ans = dfs(0);
+ return ans < trie.inf ? ans : -1;
+ }
+
+ private int dfs(int i) {
+ if (i >= target.length) {
+ return 0;
+ }
+ if (f[i] != null) {
+ return f[i];
+ }
+ f[i] = trie.inf;
+ Trie node = trie;
+ for (int j = i; j < target.length; ++j) {
+ int idx = target[j] - 'a';
+ if (node.children[idx] == null) {
+ return f[i];
+ }
+ node = node.children[idx];
+ f[i] = Math.min(f[i], node.cost + dfs(j + 1));
+ }
+ return f[i];
+ }
+}
+```
+
+#### C++
+
+```cpp
+const int inf = 1 << 29;
+
+class Trie {
+public:
+ Trie* children[26]{};
+ int cost = inf;
+
+ void insert(string& word, int cost) {
+ Trie* node = this;
+ for (char c : word) {
+ int idx = c - 'a';
+ if (!node->children[idx]) {
+ node->children[idx] = new Trie();
+ }
+ node = node->children[idx];
+ }
+ node->cost = min(node->cost, cost);
+ }
+};
+
+class Solution {
+public:
+ int minimumCost(string target, vector& words, vector& costs) {
+ Trie* trie = new Trie();
+ for (int i = 0; i < words.size(); ++i) {
+ trie->insert(words[i], costs[i]);
+ }
+ int n = target.length();
+ int f[n];
+ memset(f, 0, sizeof(f));
+ auto dfs = [&](auto&& dfs, int i) -> int {
+ if (i >= n) {
+ return 0;
+ }
+ if (f[i]) {
+ return f[i];
+ }
+ f[i] = inf;
+ Trie* node = trie;
+ for (int j = i; j < n; ++j) {
+ int idx = target[j] - 'a';
+ if (!node->children[idx]) {
+ return f[i];
+ }
+ node = node->children[idx];
+ f[i] = min(f[i], node->cost + dfs(dfs, j + 1));
+ }
+ return f[i];
+ };
+ int ans = dfs(dfs, 0);
+ return ans < inf ? ans : -1;
+ }
+};
+```
+
+#### Go
+
+```go
+const inf = 1 << 29
+
+type Trie struct {
+ children [26]*Trie
+ cost int
+}
+
+func NewTrie() *Trie {
+ return &Trie{cost: inf}
+}
+
+func (t *Trie) insert(word string, cost int) {
+ node := t
+ for _, c := range word {
+ idx := c - 'a'
+ if node.children[idx] == nil {
+ node.children[idx] = NewTrie()
+ }
+ node = node.children[idx]
+ }
+ node.cost = min(node.cost, cost)
+}
+
+func minimumCost(target string, words []string, costs []int) int {
+ trie := NewTrie()
+ for i, word := range words {
+ trie.insert(word, costs[i])
+ }
+
+ n := len(target)
+ f := make([]int, n)
+ var dfs func(int) int
+ dfs = func(i int) int {
+ if i >= n {
+ return 0
+ }
+ if f[i] != 0 {
+ return f[i]
+ }
+ f[i] = inf
+ node := trie
+ for j := i; j < n; j++ {
+ idx := target[j] - 'a'
+ if node.children[idx] == nil {
+ return f[i]
+ }
+ node = node.children[idx]
+ f[i] = min(f[i], node.cost+dfs(j+1))
+ }
+ return f[i]
+ }
+ if ans := dfs(0); ans < inf {
+ return ans
+ }
+ return -1
+}
+```
+
+#### TypeScript
+
+```ts
+const inf = 1 << 29;
+
+class Trie {
+ children: (Trie | null)[];
+ cost: number;
+
+ constructor() {
+ this.children = Array(26).fill(null);
+ this.cost = inf;
+ }
+
+ insert(word: string, cost: number): void {
+ let node: Trie = this;
+ for (const c of word) {
+ const idx = c.charCodeAt(0) - 97;
+ if (!node.children[idx]) {
+ node.children[idx] = new Trie();
+ }
+ node = node.children[idx]!;
+ }
+ node.cost = Math.min(node.cost, cost);
+ }
+}
+
+function minimumCost(target: string, words: string[], costs: number[]): number {
+ const trie = new Trie();
+ for (let i = 0; i < words.length; ++i) {
+ trie.insert(words[i], costs[i]);
+ }
+
+ const n = target.length;
+ const f: number[] = Array(n).fill(0);
+ const dfs = (i: number): number => {
+ if (i >= n) {
+ return 0;
+ }
+ if (f[i]) {
+ return f[i];
+ }
+ f[i] = inf;
+ let node: Trie | null = trie;
+ for (let j = i; j < n; ++j) {
+ const idx = target.charCodeAt(j) - 97;
+ if (!node?.children[idx]) {
+ return f[i];
+ }
+ node = node.children[idx];
+ f[i] = Math.min(f[i], node!.cost + dfs(j + 1));
+ }
+ return f[i];
+ };
+
+ const ans = dfs(0);
+ return ans < inf ? ans : -1;
+}
+```
+
+
+
+
+
+
diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README_EN.md b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README_EN.md
new file mode 100644
index 0000000000000..b5af739ba1c68
--- /dev/null
+++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README_EN.md
@@ -0,0 +1,380 @@
+---
+comments: true
+difficulty: Medium
+edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README_EN.md
+---
+
+
+
+# [3253. Construct String with Minimum Cost (Easy) 🔒](https://leetcode.com/problems/construct-string-with-minimum-cost-easy)
+
+[中文文档](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README.md)
+
+## Description
+
+
+
+You are given a string target
, an array of strings words
, and an integer array costs
, both arrays of the same length.
+
+Imagine an empty string s
.
+
+You can perform the following operation any number of times (including zero):
+
+
+ - Choose an index
i
in the range [0, words.length - 1]
.
+ - Append
words[i]
to s
.
+ - The cost of operation is
costs[i]
.
+
+
+Return the minimum cost to make s
equal to target
. If it's not possible, return -1.
+
+
+Example 1:
+
+
+
Input: target = "abcdef", words = ["abdef","abc","d","def","ef"], costs = [100,1,1,10,5]
+
+
Output: 7
+
+
Explanation:
+
+
The minimum cost can be achieved by performing the following operations:
+
+
+ - Select index 1 and append
"abc"
to s
at a cost of 1, resulting in s = "abc"
.
+ - Select index 2 and append
"d"
to s
at a cost of 1, resulting in s = "abcd"
.
+ - Select index 4 and append
"ef"
to s
at a cost of 5, resulting in s = "abcdef"
.
+
+
+
+Example 2:
+
+
+
Input: target = "aaaa", words = ["z","zz","zzz"], costs = [1,10,100]
+
+
Output: -1
+
+
Explanation:
+
+
It is impossible to make s
equal to target
, so we return -1.
+
+
+
+Constraints:
+
+
+ 1 <= target.length <= 2000
+ 1 <= words.length == costs.length <= 50
+ 1 <= words[i].length <= target.length
+ target
and words[i]
consist only of lowercase English letters.
+ 1 <= costs[i] <= 105
+
+
+
+
+## Solutions
+
+
+
+### Solution 1: Trie + Memoized Search
+
+We first create a Trie $\textit{trie}$, where each node in the Trie contains an array $\textit{children}$ of length $26$, and each element in the array is a pointer to the next node. Each node in the Trie also contains a $\textit{cost}$ variable, which represents the minimum cost from the root node to the current node.
+
+We traverse the $\textit{words}$ array, inserting each word into the Trie while updating the $\textit{cost}$ variable for each node.
+
+Next, we define a memoized search function $\textit{dfs}(i)$, which represents the minimum cost to construct the string starting from $\textit{target}[i]$. The answer is $\textit{dfs}(0)$.
+
+The calculation process of the function $\textit{dfs}(i)$ is as follows:
+
+- If $i \geq \textit{len}(\textit{target})$, it means the entire string has been constructed, so return $0$.
+- Otherwise, we start from the root node of the $\textit{trie}$ and traverse all suffixes starting from $\textit{target}[i]$, finding the minimum cost, which is the $\textit{cost}$ variable in the $\textit{trie}$, plus the result of $\textit{dfs}(j+1)$, where $j$ is the ending position of the suffix starting from $\textit{target}[i]$.
+
+Finally, if $\textit{dfs}(0) < \textit{inf}$, return $\textit{dfs}(0)$; otherwise, return $-1$.
+
+The time complexity is $O(n^2 + L)$, and the space complexity is $O(n + L)$. Here, $n$ is the length of $\textit{target}$, and $L$ is the sum of the lengths of all words in the $\textit{words}$ array.
+
+
+
+#### Python3
+
+```python
+class Trie:
+ def __init__(self):
+ self.children: List[Optional[Trie]] = [None] * 26
+ self.cost = inf
+
+ def insert(self, word: str, cost: int):
+ node = self
+ for c in word:
+ idx = ord(c) - ord("a")
+ if node.children[idx] is None:
+ node.children[idx] = Trie()
+ node = node.children[idx]
+ node.cost = min(node.cost, cost)
+
+
+class Solution:
+ def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
+ @cache
+ def dfs(i: int) -> int:
+ if i >= len(target):
+ return 0
+ ans = inf
+ node = trie
+ for j in range(i, len(target)):
+ idx = ord(target[j]) - ord("a")
+ if node.children[idx] is None:
+ return ans
+ node = node.children[idx]
+ ans = min(ans, node.cost + dfs(j + 1))
+ return ans
+
+ trie = Trie()
+ for word, cost in zip(words, costs):
+ trie.insert(word, cost)
+ ans = dfs(0)
+ return ans if ans < inf else -1
+```
+
+#### Java
+
+```java
+class Trie {
+ public final int inf = 1 << 29;
+ public Trie[] children = new Trie[26];
+ public int cost = inf;
+
+ public void insert(String word, int cost) {
+ Trie node = this;
+ for (char c : word.toCharArray()) {
+ int idx = c - 'a';
+ if (node.children[idx] == null) {
+ node.children[idx] = new Trie();
+ }
+ node = node.children[idx];
+ }
+ node.cost = Math.min(node.cost, cost);
+ }
+}
+
+class Solution {
+ private Trie trie = new Trie();
+ private char[] target;
+ private Integer[] f;
+
+ public int minimumCost(String target, String[] words, int[] costs) {
+ for (int i = 0; i < words.length; ++i) {
+ trie.insert(words[i], costs[i]);
+ }
+ this.target = target.toCharArray();
+ f = new Integer[target.length()];
+ int ans = dfs(0);
+ return ans < trie.inf ? ans : -1;
+ }
+
+ private int dfs(int i) {
+ if (i >= target.length) {
+ return 0;
+ }
+ if (f[i] != null) {
+ return f[i];
+ }
+ f[i] = trie.inf;
+ Trie node = trie;
+ for (int j = i; j < target.length; ++j) {
+ int idx = target[j] - 'a';
+ if (node.children[idx] == null) {
+ return f[i];
+ }
+ node = node.children[idx];
+ f[i] = Math.min(f[i], node.cost + dfs(j + 1));
+ }
+ return f[i];
+ }
+}
+```
+
+#### C++
+
+```cpp
+const int inf = 1 << 29;
+
+class Trie {
+public:
+ Trie* children[26]{};
+ int cost = inf;
+
+ void insert(string& word, int cost) {
+ Trie* node = this;
+ for (char c : word) {
+ int idx = c - 'a';
+ if (!node->children[idx]) {
+ node->children[idx] = new Trie();
+ }
+ node = node->children[idx];
+ }
+ node->cost = min(node->cost, cost);
+ }
+};
+
+class Solution {
+public:
+ int minimumCost(string target, vector& words, vector& costs) {
+ Trie* trie = new Trie();
+ for (int i = 0; i < words.size(); ++i) {
+ trie->insert(words[i], costs[i]);
+ }
+ int n = target.length();
+ int f[n];
+ memset(f, 0, sizeof(f));
+ auto dfs = [&](auto&& dfs, int i) -> int {
+ if (i >= n) {
+ return 0;
+ }
+ if (f[i]) {
+ return f[i];
+ }
+ f[i] = inf;
+ Trie* node = trie;
+ for (int j = i; j < n; ++j) {
+ int idx = target[j] - 'a';
+ if (!node->children[idx]) {
+ return f[i];
+ }
+ node = node->children[idx];
+ f[i] = min(f[i], node->cost + dfs(dfs, j + 1));
+ }
+ return f[i];
+ };
+ int ans = dfs(dfs, 0);
+ return ans < inf ? ans : -1;
+ }
+};
+```
+
+#### Go
+
+```go
+const inf = 1 << 29
+
+type Trie struct {
+ children [26]*Trie
+ cost int
+}
+
+func NewTrie() *Trie {
+ return &Trie{cost: inf}
+}
+
+func (t *Trie) insert(word string, cost int) {
+ node := t
+ for _, c := range word {
+ idx := c - 'a'
+ if node.children[idx] == nil {
+ node.children[idx] = NewTrie()
+ }
+ node = node.children[idx]
+ }
+ node.cost = min(node.cost, cost)
+}
+
+func minimumCost(target string, words []string, costs []int) int {
+ trie := NewTrie()
+ for i, word := range words {
+ trie.insert(word, costs[i])
+ }
+
+ n := len(target)
+ f := make([]int, n)
+ var dfs func(int) int
+ dfs = func(i int) int {
+ if i >= n {
+ return 0
+ }
+ if f[i] != 0 {
+ return f[i]
+ }
+ f[i] = inf
+ node := trie
+ for j := i; j < n; j++ {
+ idx := target[j] - 'a'
+ if node.children[idx] == nil {
+ return f[i]
+ }
+ node = node.children[idx]
+ f[i] = min(f[i], node.cost+dfs(j+1))
+ }
+ return f[i]
+ }
+ if ans := dfs(0); ans < inf {
+ return ans
+ }
+ return -1
+}
+```
+
+#### TypeScript
+
+```ts
+const inf = 1 << 29;
+
+class Trie {
+ children: (Trie | null)[];
+ cost: number;
+
+ constructor() {
+ this.children = Array(26).fill(null);
+ this.cost = inf;
+ }
+
+ insert(word: string, cost: number): void {
+ let node: Trie = this;
+ for (const c of word) {
+ const idx = c.charCodeAt(0) - 97;
+ if (!node.children[idx]) {
+ node.children[idx] = new Trie();
+ }
+ node = node.children[idx]!;
+ }
+ node.cost = Math.min(node.cost, cost);
+ }
+}
+
+function minimumCost(target: string, words: string[], costs: number[]): number {
+ const trie = new Trie();
+ for (let i = 0; i < words.length; ++i) {
+ trie.insert(words[i], costs[i]);
+ }
+
+ const n = target.length;
+ const f: number[] = Array(n).fill(0);
+ const dfs = (i: number): number => {
+ if (i >= n) {
+ return 0;
+ }
+ if (f[i]) {
+ return f[i];
+ }
+ f[i] = inf;
+ let node: Trie | null = trie;
+ for (let j = i; j < n; ++j) {
+ const idx = target.charCodeAt(j) - 97;
+ if (!node?.children[idx]) {
+ return f[i];
+ }
+ node = node.children[idx];
+ f[i] = Math.min(f[i], node!.cost + dfs(j + 1));
+ }
+ return f[i];
+ };
+
+ const ans = dfs(0);
+ return ans < inf ? ans : -1;
+}
+```
+
+
+
+
+
+
diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.cpp b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.cpp
new file mode 100644
index 0000000000000..66e33c7b7856c
--- /dev/null
+++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.cpp
@@ -0,0 +1,53 @@
+const int inf = 1 << 29;
+
+class Trie {
+public:
+ Trie* children[26]{};
+ int cost = inf;
+
+ void insert(string& word, int cost) {
+ Trie* node = this;
+ for (char c : word) {
+ int idx = c - 'a';
+ if (!node->children[idx]) {
+ node->children[idx] = new Trie();
+ }
+ node = node->children[idx];
+ }
+ node->cost = min(node->cost, cost);
+ }
+};
+
+class Solution {
+public:
+ int minimumCost(string target, vector& words, vector& costs) {
+ Trie* trie = new Trie();
+ for (int i = 0; i < words.size(); ++i) {
+ trie->insert(words[i], costs[i]);
+ }
+ int n = target.length();
+ int f[n];
+ memset(f, 0, sizeof(f));
+ auto dfs = [&](auto&& dfs, int i) -> int {
+ if (i >= n) {
+ return 0;
+ }
+ if (f[i]) {
+ return f[i];
+ }
+ f[i] = inf;
+ Trie* node = trie;
+ for (int j = i; j < n; ++j) {
+ int idx = target[j] - 'a';
+ if (!node->children[idx]) {
+ return f[i];
+ }
+ node = node->children[idx];
+ f[i] = min(f[i], node->cost + dfs(dfs, j + 1));
+ }
+ return f[i];
+ };
+ int ans = dfs(dfs, 0);
+ return ans < inf ? ans : -1;
+ }
+};
diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.go b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.go
new file mode 100644
index 0000000000000..6639a6b37671b
--- /dev/null
+++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.go
@@ -0,0 +1,56 @@
+const inf = 1 << 29
+
+type Trie struct {
+ children [26]*Trie
+ cost int
+}
+
+func NewTrie() *Trie {
+ return &Trie{cost: inf}
+}
+
+func (t *Trie) insert(word string, cost int) {
+ node := t
+ for _, c := range word {
+ idx := c - 'a'
+ if node.children[idx] == nil {
+ node.children[idx] = NewTrie()
+ }
+ node = node.children[idx]
+ }
+ node.cost = min(node.cost, cost)
+}
+
+func minimumCost(target string, words []string, costs []int) int {
+ trie := NewTrie()
+ for i, word := range words {
+ trie.insert(word, costs[i])
+ }
+
+ n := len(target)
+ f := make([]int, n)
+ var dfs func(int) int
+ dfs = func(i int) int {
+ if i >= n {
+ return 0
+ }
+ if f[i] != 0 {
+ return f[i]
+ }
+ f[i] = inf
+ node := trie
+ for j := i; j < n; j++ {
+ idx := target[j] - 'a'
+ if node.children[idx] == nil {
+ return f[i]
+ }
+ node = node.children[idx]
+ f[i] = min(f[i], node.cost+dfs(j+1))
+ }
+ return f[i]
+ }
+ if ans := dfs(0); ans < inf {
+ return ans
+ }
+ return -1
+}
diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.java b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.java
new file mode 100644
index 0000000000000..9f02d21f1c565
--- /dev/null
+++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.java
@@ -0,0 +1,53 @@
+class Trie {
+ public final int inf = 1 << 29;
+ public Trie[] children = new Trie[26];
+ public int cost = inf;
+
+ public void insert(String word, int cost) {
+ Trie node = this;
+ for (char c : word.toCharArray()) {
+ int idx = c - 'a';
+ if (node.children[idx] == null) {
+ node.children[idx] = new Trie();
+ }
+ node = node.children[idx];
+ }
+ node.cost = Math.min(node.cost, cost);
+ }
+}
+
+class Solution {
+ private Trie trie = new Trie();
+ private char[] target;
+ private Integer[] f;
+
+ public int minimumCost(String target, String[] words, int[] costs) {
+ for (int i = 0; i < words.length; ++i) {
+ trie.insert(words[i], costs[i]);
+ }
+ this.target = target.toCharArray();
+ f = new Integer[target.length()];
+ int ans = dfs(0);
+ return ans < trie.inf ? ans : -1;
+ }
+
+ private int dfs(int i) {
+ if (i >= target.length) {
+ return 0;
+ }
+ if (f[i] != null) {
+ return f[i];
+ }
+ f[i] = trie.inf;
+ Trie node = trie;
+ for (int j = i; j < target.length; ++j) {
+ int idx = target[j] - 'a';
+ if (node.children[idx] == null) {
+ return f[i];
+ }
+ node = node.children[idx];
+ f[i] = Math.min(f[i], node.cost + dfs(j + 1));
+ }
+ return f[i];
+ }
+}
diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.py b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.py
new file mode 100644
index 0000000000000..2619866316b74
--- /dev/null
+++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.py
@@ -0,0 +1,36 @@
+class Trie:
+ def __init__(self):
+ self.children: List[Optional[Trie]] = [None] * 26
+ self.cost = inf
+
+ def insert(self, word: str, cost: int):
+ node = self
+ for c in word:
+ idx = ord(c) - ord("a")
+ if node.children[idx] is None:
+ node.children[idx] = Trie()
+ node = node.children[idx]
+ node.cost = min(node.cost, cost)
+
+
+class Solution:
+ def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
+ @cache
+ def dfs(i: int) -> int:
+ if i >= len(target):
+ return 0
+ ans = inf
+ node = trie
+ for j in range(i, len(target)):
+ idx = ord(target[j]) - ord("a")
+ if node.children[idx] is None:
+ return ans
+ node = node.children[idx]
+ ans = min(ans, node.cost + dfs(j + 1))
+ return ans
+
+ trie = Trie()
+ for word, cost in zip(words, costs):
+ trie.insert(word, cost)
+ ans = dfs(0)
+ return ans if ans < inf else -1
diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.ts b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.ts
new file mode 100644
index 0000000000000..a0d76bdaa0d2b
--- /dev/null
+++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.ts
@@ -0,0 +1,55 @@
+const inf = 1 << 29;
+
+class Trie {
+ children: (Trie | null)[];
+ cost: number;
+
+ constructor() {
+ this.children = Array(26).fill(null);
+ this.cost = inf;
+ }
+
+ insert(word: string, cost: number): void {
+ let node: Trie = this;
+ for (const c of word) {
+ const idx = c.charCodeAt(0) - 97;
+ if (!node.children[idx]) {
+ node.children[idx] = new Trie();
+ }
+ node = node.children[idx]!;
+ }
+ node.cost = Math.min(node.cost, cost);
+ }
+}
+
+function minimumCost(target: string, words: string[], costs: number[]): number {
+ const trie = new Trie();
+ for (let i = 0; i < words.length; ++i) {
+ trie.insert(words[i], costs[i]);
+ }
+
+ const n = target.length;
+ const f: number[] = Array(n).fill(0);
+ const dfs = (i: number): number => {
+ if (i >= n) {
+ return 0;
+ }
+ if (f[i]) {
+ return f[i];
+ }
+ f[i] = inf;
+ let node: Trie | null = trie;
+ for (let j = i; j < n; ++j) {
+ const idx = target.charCodeAt(j) - 97;
+ if (!node?.children[idx]) {
+ return f[i];
+ }
+ node = node.children[idx];
+ f[i] = Math.min(f[i], node!.cost + dfs(j + 1));
+ }
+ return f[i];
+ };
+
+ const ans = dfs(0);
+ return ans < inf ? ans : -1;
+}
diff --git a/solution/README.md b/solution/README.md
index c9792a8515323..7ba6ac5f01354 100644
--- a/solution/README.md
+++ b/solution/README.md
@@ -3263,6 +3263,7 @@
| 3250 | [单调数组对的数目 I](/solution/3200-3299/3250.Find%20the%20Count%20of%20Monotonic%20Pairs%20I/README.md) | `数组`,`数学`,`动态规划`,`组合数学`,`前缀和` | 困难 | 第 410 场周赛 |
| 3251 | [单调数组对的数目 II](/solution/3200-3299/3251.Find%20the%20Count%20of%20Monotonic%20Pairs%20II/README.md) | `数组`,`数学`,`动态规划`,`组合数学`,`前缀和` | 困难 | 第 410 场周赛 |
| 3252 | [英超积分榜排名 II](/solution/3200-3299/3252.Premier%20League%20Table%20Ranking%20II/README.md) | `数据库` | 中等 | 🔒 |
+| 3253 | [Construct String with Minimum Cost (Easy)](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README.md) | | 中等 | 🔒 |
## 版权
diff --git a/solution/README_EN.md b/solution/README_EN.md
index 4c818e2d17786..67e8466282339 100644
--- a/solution/README_EN.md
+++ b/solution/README_EN.md
@@ -3261,6 +3261,7 @@ Press Control + F(or Command + F on
| 3250 | [Find the Count of Monotonic Pairs I](/solution/3200-3299/3250.Find%20the%20Count%20of%20Monotonic%20Pairs%20I/README_EN.md) | `Array`,`Math`,`Dynamic Programming`,`Combinatorics`,`Prefix Sum` | Hard | Weekly Contest 410 |
| 3251 | [Find the Count of Monotonic Pairs II](/solution/3200-3299/3251.Find%20the%20Count%20of%20Monotonic%20Pairs%20II/README_EN.md) | `Array`,`Math`,`Dynamic Programming`,`Combinatorics`,`Prefix Sum` | Hard | Weekly Contest 410 |
| 3252 | [Premier League Table Ranking II](/solution/3200-3299/3252.Premier%20League%20Table%20Ranking%20II/README_EN.md) | `Database` | Medium | 🔒 |
+| 3253 | [Construct String with Minimum Cost (Easy)](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README_EN.md) | | Medium | 🔒 |
## Copyright