diff --git a/solution/2500-2599/2582.Pass the Pillow/README.md b/solution/2500-2599/2582.Pass the Pillow/README.md
index 42d9357793c80..7995ffa41a767 100644
--- a/solution/2500-2599/2582.Pass the Pillow/README.md
+++ b/solution/2500-2599/2582.Pass the Pillow/README.md
@@ -19,9 +19,7 @@ tags:
-
n
个人站成一排,按从 1
到 n
编号。
-
-最初,排在队首的第一个人拿着一个枕头。每秒钟,拿着枕头的人会将枕头传递给队伍中的下一个人。一旦枕头到达队首或队尾,传递方向就会改变,队伍会继续沿相反方向传递枕头。
+n
个人站成一排,按从 1
到 n
编号。最初,排在队首的第一个人拿着一个枕头。每秒钟,拿着枕头的人会将枕头传递给队伍中的下一个人。一旦枕头到达队首或队尾,传递方向就会改变,队伍会继续沿相反方向传递枕头。
- 例如,当枕头到达第
n
个人时,TA 会将枕头传递给第 n - 1
个人,然后传递给第 n - 2
个人,依此类推。
diff --git a/solution/3100-3199/3100.Water Bottles II/Solution.rs b/solution/3100-3199/3100.Water Bottles II/Solution.rs
index bf6e5da737565..eedc8a37aa3c6 100644
--- a/solution/3100-3199/3100.Water Bottles II/Solution.rs
+++ b/solution/3100-3199/3100.Water Bottles II/Solution.rs
@@ -1,14 +1,14 @@
impl Solution {
pub fn max_bottles_drunk(mut num_bottles: i32, mut num_exchange: i32) -> i32 {
let mut ans = num_bottles;
-
+
while num_bottles >= num_exchange {
num_bottles -= num_exchange;
num_exchange += 1;
ans += 1;
num_bottles += 1;
}
-
+
ans
}
}
diff --git a/solution/3200-3299/3213.Construct String with Minimum Cost/README.md b/solution/3200-3299/3213.Construct String with Minimum Cost/README.md
index 93eefd8d49bab..7433c69d2fff4 100644
--- a/solution/3200-3299/3213.Construct String with Minimum Cost/README.md
+++ b/solution/3200-3299/3213.Construct String with Minimum Cost/README.md
@@ -77,32 +77,268 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3213.Co
-### 方法一
+### 方法一:字符串哈希 + 动态规划 + 枚举长度
+
+我们定义 $f[i]$ 表示构造 $\textit{target}$ 前 $i$ 个字符的最小代价,初始时 $f[0] = 0$,其余值均为无穷大。答案为 $f[n]$,其中 $n$ 是 $\textit{target}$ 的长度。
+
+对于当前 $f[i]$,考虑枚举单词的长度 $j$,如果 $j \leq i$,那么我们可以考虑从 $i - j + 1$ 到 $i$ 这段区间的哈希值,如果这个哈希值对应的单词存在,那么我们可以转移从 $f[i - j]$ 转移到 $f[i]$。状态转移方程如下:
+
+$$
+f[i] = \min(f[i], f[i - j] + \textit{cost}[k])
+$$
+
+其中 $textit{cost}[k]$ 表示长度为 $j$ 的单词且哈希值与 $\textit{target}[i - j + 1, i]$ 相同的单词的最小代价。
+
+时间复杂度 $O(n \times \sqrt{L})$,空间复杂度 $O(n)$。其中 $n$ 是 $\textit{target}$ 的长度,而 $L$ 是数组 $\textit{words}$ 中所有单词的长度之和。
#### Python3
```python
-
+class Solution:
+ def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
+ base, mod = 13331, 998244353
+ n = len(target)
+ h = [0] * (n + 1)
+ p = [1] * (n + 1)
+ for i, c in enumerate(target, 1):
+ h[i] = (h[i - 1] * base + ord(c)) % mod
+ p[i] = (p[i - 1] * base) % mod
+ f = [0] + [inf] * n
+ ss = sorted(set(map(len, words)))
+ d = defaultdict(lambda: inf)
+ min = lambda a, b: a if a < b else b
+ for w, c in zip(words, costs):
+ x = 0
+ for ch in w:
+ x = (x * base + ord(ch)) % mod
+ d[x] = min(d[x], c)
+ for i in range(1, n + 1):
+ for j in ss:
+ if j > i:
+ break
+ x = (h[i] - h[i - j] * p[j]) % mod
+ f[i] = min(f[i], f[i - j] + d[x])
+ return f[n] if f[n] < inf else -1
```
#### Java
```java
-
+class Hashing {
+ private final long[] p;
+ private final long[] h;
+ private final long mod;
+
+ public Hashing(String word, long base, int mod) {
+ int n = word.length();
+ p = new long[n + 1];
+ h = new long[n + 1];
+ p[0] = 1;
+ this.mod = mod;
+ for (int i = 1; i <= n; i++) {
+ p[i] = p[i - 1] * base % mod;
+ h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
+ }
+ }
+
+ public long query(int l, int r) {
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
+ }
+}
+
+class Solution {
+ public int minimumCost(String target, String[] words, int[] costs) {
+ final int base = 13331;
+ final int mod = 998244353;
+ final int inf = Integer.MAX_VALUE / 2;
+
+ int n = target.length();
+ Hashing hashing = new Hashing(target, base, mod);
+
+ int[] f = new int[n + 1];
+ Arrays.fill(f, inf);
+ f[0] = 0;
+
+ TreeSet ss = new TreeSet<>();
+ for (String w : words) {
+ ss.add(w.length());
+ }
+
+ Map d = new HashMap<>();
+ for (int i = 0; i < words.length; i++) {
+ long x = 0;
+ for (char c : words[i].toCharArray()) {
+ x = (x * base + c) % mod;
+ }
+ d.merge(x, costs[i], Integer::min);
+ }
+
+ for (int i = 1; i <= n; i++) {
+ for (int j : ss) {
+ if (j > i) {
+ break;
+ }
+ long x = hashing.query(i - j + 1, i);
+ f[i] = Math.min(f[i], f[i - j] + d.getOrDefault(x, inf));
+ }
+ }
+
+ return f[n] >= inf ? -1 : f[n];
+ }
+}
```
#### C++
```cpp
-
+class Hashing {
+private:
+ vector p, h;
+ long mod;
+
+public:
+ Hashing(const string& word, long base, long mod)
+ : p(word.size() + 1, 1)
+ , h(word.size() + 1, 0)
+ , mod(mod) {
+ for (int i = 1; i <= word.size(); ++i) {
+ p[i] = p[i - 1] * base % mod;
+ h[i] = (h[i - 1] * base + word[i - 1]) % mod;
+ }
+ }
+
+ long query(int l, int r) {
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
+ }
+};
+
+class Solution {
+public:
+ int minimumCost(string target, vector& words, vector& costs) {
+ const int base = 13331;
+ const int mod = 998244353;
+ const int inf = INT_MAX / 2;
+
+ int n = target.size();
+ Hashing hashing(target, base, mod);
+
+ vector f(n + 1, inf);
+ f[0] = 0;
+
+ set ss;
+ for (const string& w : words) {
+ ss.insert(w.size());
+ }
+
+ unordered_map d;
+ for (int i = 0; i < words.size(); ++i) {
+ long x = 0;
+ for (char c : words[i]) {
+ x = (x * base + c) % mod;
+ }
+ d[x] = d.find(x) == d.end() ? costs[i] : min(d[x], costs[i]);
+ }
+
+ for (int i = 1; i <= n; ++i) {
+ for (int j : ss) {
+ if (j > i) {
+ break;
+ }
+ long x = hashing.query(i - j + 1, i);
+ if (d.contains(x)) {
+ f[i] = min(f[i], f[i - j] + d[x]);
+ }
+ }
+ }
+
+ return f[n] >= inf ? -1 : f[n];
+ }
+};
```
#### Go
```go
-
+type Hashing struct {
+ p []int64
+ h []int64
+ mod int64
+}
+
+func NewHashing(word string, base, mod int64) *Hashing {
+ n := len(word)
+ p := make([]int64, n+1)
+ h := make([]int64, n+1)
+ p[0] = 1
+ for i := 1; i <= n; i++ {
+ p[i] = p[i-1] * base % mod
+ h[i] = (h[i-1]*base + int64(word[i-1])) % mod
+ }
+ return &Hashing{p, h, mod}
+}
+
+func (hs *Hashing) query(l, r int) int64 {
+ return (hs.h[r] - hs.h[l-1]*hs.p[r-l+1]%hs.mod + hs.mod) % hs.mod
+}
+
+func minimumCost(target string, words []string, costs []int) int {
+ const base = 13331
+ const mod = 998244353
+ const inf = math.MaxInt32 / 2
+
+ n := len(target)
+ hashing := NewHashing(target, base, mod)
+
+ f := make([]int, n+1)
+ for i := range f {
+ f[i] = inf
+ }
+ f[0] = 0
+
+ ss := make(map[int]struct{})
+ for _, w := range words {
+ ss[len(w)] = struct{}{}
+ }
+ lengths := make([]int, 0, len(ss))
+ for length := range ss {
+ lengths = append(lengths, length)
+ }
+ sort.Ints(lengths)
+
+ d := make(map[int64]int)
+ for i, w := range words {
+ var x int64
+ for _, c := range w {
+ x = (x*base + int64(c)) % mod
+ }
+ if existingCost, exists := d[x]; exists {
+ if costs[i] < existingCost {
+ d[x] = costs[i]
+ }
+ } else {
+ d[x] = costs[i]
+ }
+ }
+
+ for i := 1; i <= n; i++ {
+ for _, j := range lengths {
+ if j > i {
+ break
+ }
+ x := hashing.query(i-j+1, i)
+ if cost, ok := d[x]; ok {
+ f[i] = min(f[i], f[i-j]+cost)
+ }
+ }
+ }
+
+ if f[n] >= inf {
+ return -1
+ }
+ return f[n]
+}
```
diff --git a/solution/3200-3299/3213.Construct String with Minimum Cost/README_EN.md b/solution/3200-3299/3213.Construct String with Minimum Cost/README_EN.md
index c85b5ffffcb51..67d866fafefcd 100644
--- a/solution/3200-3299/3213.Construct String with Minimum Cost/README_EN.md
+++ b/solution/3200-3299/3213.Construct String with Minimum Cost/README_EN.md
@@ -77,32 +77,268 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3213.Co
-### Solution 1
+### Solution 1: String Hashing + Dynamic Programming + Enumerating Length
+
+We define $f[i]$ as the minimum cost to construct the first $i$ characters of $\textit{target}$, with the initial condition $f[0] = 0$ and all other values set to infinity. The answer is $f[n]$, where $n$ is the length of $\textit{target}$.
+
+For the current $f[i]$, consider enumerating the length $j$ of the word. If $j \leq i$, then we can consider the hash value of the segment from $i - j + 1$ to $i$. If this hash value corresponds to an existing word, then we can transition from $f[i - j]$ to $f[i]$. The state transition equation is as follows:
+
+$$
+f[i] = \min(f[i], f[i - j] + \textit{cost}[k])
+$$
+
+where $\textit{cost}[k]$ represents the minimum cost of a word of length $j$ whose hash value matches $\textit{target}[i - j + 1, i]$.
+
+The time complexity is $O(n \times \sqrt{L})$, and the space complexity is $O(n)$. Here, $n$ is the length of $\textit{target}$, and $L$ is the sum of the lengths of all words in the array $\textit{words}$.
#### Python3
```python
-
+class Solution:
+ def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
+ base, mod = 13331, 998244353
+ n = len(target)
+ h = [0] * (n + 1)
+ p = [1] * (n + 1)
+ for i, c in enumerate(target, 1):
+ h[i] = (h[i - 1] * base + ord(c)) % mod
+ p[i] = (p[i - 1] * base) % mod
+ f = [0] + [inf] * n
+ ss = sorted(set(map(len, words)))
+ d = defaultdict(lambda: inf)
+ min = lambda a, b: a if a < b else b
+ for w, c in zip(words, costs):
+ x = 0
+ for ch in w:
+ x = (x * base + ord(ch)) % mod
+ d[x] = min(d[x], c)
+ for i in range(1, n + 1):
+ for j in ss:
+ if j > i:
+ break
+ x = (h[i] - h[i - j] * p[j]) % mod
+ f[i] = min(f[i], f[i - j] + d[x])
+ return f[n] if f[n] < inf else -1
```
#### Java
```java
-
+class Hashing {
+ private final long[] p;
+ private final long[] h;
+ private final long mod;
+
+ public Hashing(String word, long base, int mod) {
+ int n = word.length();
+ p = new long[n + 1];
+ h = new long[n + 1];
+ p[0] = 1;
+ this.mod = mod;
+ for (int i = 1; i <= n; i++) {
+ p[i] = p[i - 1] * base % mod;
+ h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
+ }
+ }
+
+ public long query(int l, int r) {
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
+ }
+}
+
+class Solution {
+ public int minimumCost(String target, String[] words, int[] costs) {
+ final int base = 13331;
+ final int mod = 998244353;
+ final int inf = Integer.MAX_VALUE / 2;
+
+ int n = target.length();
+ Hashing hashing = new Hashing(target, base, mod);
+
+ int[] f = new int[n + 1];
+ Arrays.fill(f, inf);
+ f[0] = 0;
+
+ TreeSet ss = new TreeSet<>();
+ for (String w : words) {
+ ss.add(w.length());
+ }
+
+ Map d = new HashMap<>();
+ for (int i = 0; i < words.length; i++) {
+ long x = 0;
+ for (char c : words[i].toCharArray()) {
+ x = (x * base + c) % mod;
+ }
+ d.merge(x, costs[i], Integer::min);
+ }
+
+ for (int i = 1; i <= n; i++) {
+ for (int j : ss) {
+ if (j > i) {
+ break;
+ }
+ long x = hashing.query(i - j + 1, i);
+ f[i] = Math.min(f[i], f[i - j] + d.getOrDefault(x, inf));
+ }
+ }
+
+ return f[n] >= inf ? -1 : f[n];
+ }
+}
```
#### C++
```cpp
-
+class Hashing {
+private:
+ vector p, h;
+ long mod;
+
+public:
+ Hashing(const string& word, long base, long mod)
+ : p(word.size() + 1, 1)
+ , h(word.size() + 1, 0)
+ , mod(mod) {
+ for (int i = 1; i <= word.size(); ++i) {
+ p[i] = p[i - 1] * base % mod;
+ h[i] = (h[i - 1] * base + word[i - 1]) % mod;
+ }
+ }
+
+ long query(int l, int r) {
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
+ }
+};
+
+class Solution {
+public:
+ int minimumCost(string target, vector& words, vector& costs) {
+ const int base = 13331;
+ const int mod = 998244353;
+ const int inf = INT_MAX / 2;
+
+ int n = target.size();
+ Hashing hashing(target, base, mod);
+
+ vector f(n + 1, inf);
+ f[0] = 0;
+
+ set ss;
+ for (const string& w : words) {
+ ss.insert(w.size());
+ }
+
+ unordered_map d;
+ for (int i = 0; i < words.size(); ++i) {
+ long x = 0;
+ for (char c : words[i]) {
+ x = (x * base + c) % mod;
+ }
+ d[x] = d.find(x) == d.end() ? costs[i] : min(d[x], costs[i]);
+ }
+
+ for (int i = 1; i <= n; ++i) {
+ for (int j : ss) {
+ if (j > i) {
+ break;
+ }
+ long x = hashing.query(i - j + 1, i);
+ if (d.contains(x)) {
+ f[i] = min(f[i], f[i - j] + d[x]);
+ }
+ }
+ }
+
+ return f[n] >= inf ? -1 : f[n];
+ }
+};
```
#### Go
```go
-
+type Hashing struct {
+ p []int64
+ h []int64
+ mod int64
+}
+
+func NewHashing(word string, base, mod int64) *Hashing {
+ n := len(word)
+ p := make([]int64, n+1)
+ h := make([]int64, n+1)
+ p[0] = 1
+ for i := 1; i <= n; i++ {
+ p[i] = p[i-1] * base % mod
+ h[i] = (h[i-1]*base + int64(word[i-1])) % mod
+ }
+ return &Hashing{p, h, mod}
+}
+
+func (hs *Hashing) query(l, r int) int64 {
+ return (hs.h[r] - hs.h[l-1]*hs.p[r-l+1]%hs.mod + hs.mod) % hs.mod
+}
+
+func minimumCost(target string, words []string, costs []int) int {
+ const base = 13331
+ const mod = 998244353
+ const inf = math.MaxInt32 / 2
+
+ n := len(target)
+ hashing := NewHashing(target, base, mod)
+
+ f := make([]int, n+1)
+ for i := range f {
+ f[i] = inf
+ }
+ f[0] = 0
+
+ ss := make(map[int]struct{})
+ for _, w := range words {
+ ss[len(w)] = struct{}{}
+ }
+ lengths := make([]int, 0, len(ss))
+ for length := range ss {
+ lengths = append(lengths, length)
+ }
+ sort.Ints(lengths)
+
+ d := make(map[int64]int)
+ for i, w := range words {
+ var x int64
+ for _, c := range w {
+ x = (x*base + int64(c)) % mod
+ }
+ if existingCost, exists := d[x]; exists {
+ if costs[i] < existingCost {
+ d[x] = costs[i]
+ }
+ } else {
+ d[x] = costs[i]
+ }
+ }
+
+ for i := 1; i <= n; i++ {
+ for _, j := range lengths {
+ if j > i {
+ break
+ }
+ x := hashing.query(i-j+1, i)
+ if cost, ok := d[x]; ok {
+ f[i] = min(f[i], f[i-j]+cost)
+ }
+ }
+ }
+
+ if f[n] >= inf {
+ return -1
+ }
+ return f[n]
+}
```
diff --git a/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.cpp b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.cpp
new file mode 100644
index 0000000000000..02ddfbfb5cf6e
--- /dev/null
+++ b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.cpp
@@ -0,0 +1,63 @@
+class Hashing {
+private:
+ vector p, h;
+ long mod;
+
+public:
+ Hashing(const string& word, long base, long mod)
+ : p(word.size() + 1, 1)
+ , h(word.size() + 1, 0)
+ , mod(mod) {
+ for (int i = 1; i <= word.size(); ++i) {
+ p[i] = p[i - 1] * base % mod;
+ h[i] = (h[i - 1] * base + word[i - 1]) % mod;
+ }
+ }
+
+ long query(int l, int r) {
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
+ }
+};
+
+class Solution {
+public:
+ int minimumCost(string target, vector& words, vector& costs) {
+ const int base = 13331;
+ const int mod = 998244353;
+ const int inf = INT_MAX / 2;
+
+ int n = target.size();
+ Hashing hashing(target, base, mod);
+
+ vector f(n + 1, inf);
+ f[0] = 0;
+
+ set ss;
+ for (const string& w : words) {
+ ss.insert(w.size());
+ }
+
+ unordered_map d;
+ for (int i = 0; i < words.size(); ++i) {
+ long x = 0;
+ for (char c : words[i]) {
+ x = (x * base + c) % mod;
+ }
+ d[x] = d.find(x) == d.end() ? costs[i] : min(d[x], costs[i]);
+ }
+
+ for (int i = 1; i <= n; ++i) {
+ for (int j : ss) {
+ if (j > i) {
+ break;
+ }
+ long x = hashing.query(i - j + 1, i);
+ if (d.contains(x)) {
+ f[i] = min(f[i], f[i - j] + d[x]);
+ }
+ }
+ }
+
+ return f[n] >= inf ? -1 : f[n];
+ }
+};
\ No newline at end of file
diff --git a/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.go b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.go
new file mode 100644
index 0000000000000..826c9050cbedf
--- /dev/null
+++ b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.go
@@ -0,0 +1,78 @@
+type Hashing struct {
+ p []int64
+ h []int64
+ mod int64
+}
+
+func NewHashing(word string, base, mod int64) *Hashing {
+ n := len(word)
+ p := make([]int64, n+1)
+ h := make([]int64, n+1)
+ p[0] = 1
+ for i := 1; i <= n; i++ {
+ p[i] = p[i-1] * base % mod
+ h[i] = (h[i-1]*base + int64(word[i-1])) % mod
+ }
+ return &Hashing{p, h, mod}
+}
+
+func (hs *Hashing) query(l, r int) int64 {
+ return (hs.h[r] - hs.h[l-1]*hs.p[r-l+1]%hs.mod + hs.mod) % hs.mod
+}
+
+func minimumCost(target string, words []string, costs []int) int {
+ const base = 13331
+ const mod = 998244353
+ const inf = math.MaxInt32 / 2
+
+ n := len(target)
+ hashing := NewHashing(target, base, mod)
+
+ f := make([]int, n+1)
+ for i := range f {
+ f[i] = inf
+ }
+ f[0] = 0
+
+ ss := make(map[int]struct{})
+ for _, w := range words {
+ ss[len(w)] = struct{}{}
+ }
+ lengths := make([]int, 0, len(ss))
+ for length := range ss {
+ lengths = append(lengths, length)
+ }
+ sort.Ints(lengths)
+
+ d := make(map[int64]int)
+ for i, w := range words {
+ var x int64
+ for _, c := range w {
+ x = (x*base + int64(c)) % mod
+ }
+ if existingCost, exists := d[x]; exists {
+ if costs[i] < existingCost {
+ d[x] = costs[i]
+ }
+ } else {
+ d[x] = costs[i]
+ }
+ }
+
+ for i := 1; i <= n; i++ {
+ for _, j := range lengths {
+ if j > i {
+ break
+ }
+ x := hashing.query(i-j+1, i)
+ if cost, ok := d[x]; ok {
+ f[i] = min(f[i], f[i-j]+cost)
+ }
+ }
+ }
+
+ if f[n] >= inf {
+ return -1
+ }
+ return f[n]
+}
\ No newline at end of file
diff --git a/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.java b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.java
new file mode 100644
index 0000000000000..bc881c4c4efdc
--- /dev/null
+++ b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.java
@@ -0,0 +1,62 @@
+class Hashing {
+ private final long[] p;
+ private final long[] h;
+ private final long mod;
+
+ public Hashing(String word, long base, int mod) {
+ int n = word.length();
+ p = new long[n + 1];
+ h = new long[n + 1];
+ p[0] = 1;
+ this.mod = mod;
+ for (int i = 1; i <= n; i++) {
+ p[i] = p[i - 1] * base % mod;
+ h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
+ }
+ }
+
+ public long query(int l, int r) {
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
+ }
+}
+
+class Solution {
+ public int minimumCost(String target, String[] words, int[] costs) {
+ final int base = 13331;
+ final int mod = 998244353;
+ final int inf = Integer.MAX_VALUE / 2;
+
+ int n = target.length();
+ Hashing hashing = new Hashing(target, base, mod);
+
+ int[] f = new int[n + 1];
+ Arrays.fill(f, inf);
+ f[0] = 0;
+
+ TreeSet ss = new TreeSet<>();
+ for (String w : words) {
+ ss.add(w.length());
+ }
+
+ Map d = new HashMap<>();
+ for (int i = 0; i < words.length; i++) {
+ long x = 0;
+ for (char c : words[i].toCharArray()) {
+ x = (x * base + c) % mod;
+ }
+ d.merge(x, costs[i], Integer::min);
+ }
+
+ for (int i = 1; i <= n; i++) {
+ for (int j : ss) {
+ if (j > i) {
+ break;
+ }
+ long x = hashing.query(i - j + 1, i);
+ f[i] = Math.min(f[i], f[i - j] + d.getOrDefault(x, inf));
+ }
+ }
+
+ return f[n] >= inf ? -1 : f[n];
+ }
+}
\ No newline at end of file
diff --git a/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.py b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.py
new file mode 100644
index 0000000000000..541d9f16e893f
--- /dev/null
+++ b/solution/3200-3299/3213.Construct String with Minimum Cost/Solution.py
@@ -0,0 +1,25 @@
+class Solution:
+ def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
+ base, mod = 13331, 998244353
+ n = len(target)
+ h = [0] * (n + 1)
+ p = [1] * (n + 1)
+ for i, c in enumerate(target, 1):
+ h[i] = (h[i - 1] * base + ord(c)) % mod
+ p[i] = (p[i - 1] * base) % mod
+ f = [0] + [inf] * n
+ ss = sorted(set(map(len, words)))
+ d = defaultdict(lambda: inf)
+ min = lambda a, b: a if a < b else b
+ for w, c in zip(words, costs):
+ x = 0
+ for ch in w:
+ x = (x * base + ord(ch)) % mod
+ d[x] = min(d[x], c)
+ for i in range(1, n + 1):
+ for j in ss:
+ if j > i:
+ break
+ x = (h[i] - h[i - j] * p[j]) % mod
+ f[i] = min(f[i], f[i - j] + d[x])
+ return f[n] if f[n] < inf else -1