diff --git a/src/main/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/Solution.kt b/src/main/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/Solution.kt
new file mode 100644
index 00000000..4ddfabf7
--- /dev/null
+++ b/src/main/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/Solution.kt
@@ -0,0 +1,19 @@
+package g3501_3600.s3566_partition_array_into_two_equal_product_subsets
+
+// #Medium #Array #Bit_Manipulation #Recursion #Enumeration
+// #2025_06_01_Time_1_ms_(100.00%)_Space_42.26_MB_(100.00%)
+
+class Solution {
+ fun checkEqualPartitions(nums: IntArray, target: Long): Boolean {
+ for (num in nums) {
+ if (target % num != 0L) {
+ return false
+ }
+ }
+ var pro: Long = 1
+ for (n in nums) {
+ pro *= n
+ }
+ return pro == target * target
+ }
+}
diff --git a/src/main/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/readme.md b/src/main/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/readme.md
new file mode 100644
index 00000000..74bdaf0d
--- /dev/null
+++ b/src/main/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/readme.md
@@ -0,0 +1,34 @@
+3566\. Partition Array into Two Equal Product Subsets
+
+Medium
+
+You are given an integer array `nums` containing **distinct** positive integers and an integer `target`.
+
+Determine if you can partition `nums` into two **non-empty** **disjoint** **subsets**, with each element belonging to **exactly one** subset, such that the product of the elements in each subset is equal to `target`.
+
+Return `true` if such a partition exists and `false` otherwise.
+
+A **subset** of an array is a selection of elements of the array.
+
+**Example 1:**
+
+**Input:** nums = [3,1,6,8,4], target = 24
+
+**Output:** true
+
+**Explanation:** The subsets `[3, 8]` and `[1, 6, 4]` each have a product of 24. Hence, the output is true.
+
+**Example 2:**
+
+**Input:** nums = [2,5,3,7], target = 15
+
+**Output:** false
+
+**Explanation:** There is no way to partition `nums` into two non-empty disjoint subsets such that both subsets have a product of 15. Hence, the output is false.
+
+**Constraints:**
+
+* `3 <= nums.length <= 12`
+* 1 <= target <= 1015
+* `1 <= nums[i] <= 100`
+* All elements of `nums` are **distinct**.
\ No newline at end of file
diff --git a/src/main/kotlin/g3501_3600/s3567_minimum_absolute_difference_in_sliding_submatrix/Solution.kt b/src/main/kotlin/g3501_3600/s3567_minimum_absolute_difference_in_sliding_submatrix/Solution.kt
new file mode 100644
index 00000000..c1c2dc0e
--- /dev/null
+++ b/src/main/kotlin/g3501_3600/s3567_minimum_absolute_difference_in_sliding_submatrix/Solution.kt
@@ -0,0 +1,37 @@
+package g3501_3600.s3567_minimum_absolute_difference_in_sliding_submatrix
+
+// #Medium #Array #Sorting #Matrix #2025_06_01_Time_18_ms_(100.00%)_Space_53.66_MB_(25.00%)
+
+import kotlin.math.min
+
+class Solution {
+ fun minAbsDiff(grid: Array, k: Int): Array {
+ val rows = grid.size
+ val cols = grid[0].size
+ val result = Array(rows - k + 1) { IntArray(cols - k + 1) }
+ for (x in 0..rows - k) {
+ for (y in 0..cols - k) {
+ val size = k * k
+ val elements = IntArray(size)
+ var idx = 0
+ for (i in x..-105 <= grid[i][j] <= 105
+* `1 <= k <= min(m, n)`
\ No newline at end of file
diff --git a/src/main/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/Solution.kt b/src/main/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/Solution.kt
new file mode 100644
index 00000000..846ca8a9
--- /dev/null
+++ b/src/main/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/Solution.kt
@@ -0,0 +1,83 @@
+package g3501_3600.s3568_minimum_moves_to_clean_the_classroom
+
+// #Medium #Array #Hash_Table #Breadth_First_Search #Matrix #Bit_Manipulation
+// #2025_06_01_Time_149_ms_(100.00%)_Space_64.20_MB_(100.00%)
+
+import java.util.ArrayDeque
+import java.util.Queue
+
+class Solution {
+ private class State(var x: Int, var y: Int, var energy: Int, var mask: Int, var steps: Int)
+
+ fun minMoves(classroom: Array, energy: Int): Int {
+ val m = classroom.size
+ val n = classroom[0].length
+ val grid = Array(m) { CharArray(n) }
+ for (i in 0.. = ArrayList()
+ for (i in 0..> =
+ Array>(m) { Array(n) { IntArray(1 shl totalLitter) } }
+ for (layer in visited) {
+ for (row in layer) {
+ row.fill(-1)
+ }
+ }
+ val queue: Queue = ArrayDeque()
+ queue.offer(State(startX, startY, energy, 0, 0))
+ visited[startX][startY][0] = energy
+ val dirs = arrayOf(intArrayOf(0, 1), intArrayOf(1, 0), intArrayOf(0, -1), intArrayOf(-1, 0))
+ while (queue.isNotEmpty()) {
+ val curr = queue.poll()
+ if (curr.mask == allMask) {
+ return curr.steps
+ }
+ for (dir in dirs) {
+ val nx = curr.x + dir[0]
+ val ny = curr.y + dir[1]
+ if (nx < 0 || ny < 0 || nx >= m || ny >= n || grid[nx][ny] == 'X') {
+ continue
+ }
+ var nextEnergy = curr.energy - 1
+ if (nextEnergy < 0) {
+ continue
+ }
+ val cell = grid[nx][ny]
+ if (cell == 'R') {
+ nextEnergy = energy
+ }
+ var nextMask = curr.mask
+ if (cell == 'L') {
+ for (i in lumetarkon.indices) {
+ val pos = lumetarkon[i]
+ if (pos[0] == nx && pos[1] == ny) {
+ nextMask = nextMask or (1 shl i)
+ break
+ }
+ }
+ }
+ if (visited[nx][ny][nextMask] < nextEnergy) {
+ visited[nx][ny][nextMask] = nextEnergy
+ queue.offer(State(nx, ny, nextEnergy, nextMask, curr.steps + 1))
+ }
+ }
+ }
+ return -1
+ }
+}
diff --git a/src/main/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/readme.md b/src/main/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/readme.md
new file mode 100644
index 00000000..421faa12
--- /dev/null
+++ b/src/main/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/readme.md
@@ -0,0 +1,66 @@
+3568\. Minimum Moves to Clean the Classroom
+
+Medium
+
+You are given an `m x n` grid `classroom` where a student volunteer is tasked with cleaning up litter scattered around the room. Each cell in the grid is one of the following:
+
+* `'S'`: Starting position of the student
+* `'L'`: Litter that must be collected (once collected, the cell becomes empty)
+* `'R'`: Reset area that restores the student's energy to full capacity, regardless of their current energy level (can be used multiple times)
+* `'X'`: Obstacle the student cannot pass through
+* `'.'`: Empty space
+
+You are also given an integer `energy`, representing the student's maximum energy capacity. The student starts with this energy from the starting position `'S'`.
+
+Each move to an adjacent cell (up, down, left, or right) costs 1 unit of energy. If the energy reaches 0, the student can only continue if they are on a reset area `'R'`, which resets the energy to its **maximum** capacity `energy`.
+
+Return the **minimum** number of moves required to collect all litter items, or `-1` if it's impossible.
+
+**Example 1:**
+
+**Input:** classroom = ["S.", "XL"], energy = 2
+
+**Output:** 2
+
+**Explanation:**
+
+* The student starts at cell `(0, 0)` with 2 units of energy.
+* Since cell `(1, 0)` contains an obstacle 'X', the student cannot move directly downward.
+* A valid sequence of moves to collect all litter is as follows:
+ * Move 1: From `(0, 0)` → `(0, 1)` with 1 unit of energy and 1 unit remaining.
+ * Move 2: From `(0, 1)` → `(1, 1)` to collect the litter `'L'`.
+* The student collects all the litter using 2 moves. Thus, the output is 2.
+
+**Example 2:**
+
+**Input:** classroom = ["LS", "RL"], energy = 4
+
+**Output:** 3
+
+**Explanation:**
+
+* The student starts at cell `(0, 1)` with 4 units of energy.
+* A valid sequence of moves to collect all litter is as follows:
+ * Move 1: From `(0, 1)` → `(0, 0)` to collect the first litter `'L'` with 1 unit of energy used and 3 units remaining.
+ * Move 2: From `(0, 0)` → `(1, 0)` to `'R'` to reset and restore energy back to 4.
+ * Move 3: From `(1, 0)` → `(1, 1)` to collect the second litter `'L'`.
+* The student collects all the litter using 3 moves. Thus, the output is 3.
+
+**Example 3:**
+
+**Input:** classroom = ["L.S", "RXL"], energy = 3
+
+**Output:** \-1
+
+**Explanation:**
+
+No valid path collects all `'L'`.
+
+**Constraints:**
+
+* `1 <= m == classroom.length <= 20`
+* `1 <= n == classroom[i].length <= 20`
+* `classroom[i][j]` is one of `'S'`, `'L'`, `'R'`, `'X'`, or `'.'`
+* `1 <= energy <= 50`
+* There is exactly **one** `'S'` in the grid.
+* There are **at most** 10 `'L'` cells in the grid.
\ No newline at end of file
diff --git a/src/main/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/Solution.kt b/src/main/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/Solution.kt
new file mode 100644
index 00000000..3f981219
--- /dev/null
+++ b/src/main/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/Solution.kt
@@ -0,0 +1,165 @@
+package g3501_3600.s3569_maximize_count_of_distinct_primes_after_split
+
+// #Hard #Array #Math #Segment_Tree #Number_Theory
+// #2025_06_01_Time_441_ms_(100.00%)_Space_98.42_MB_(100.00%)
+
+import java.util.TreeSet
+import kotlin.math.max
+import kotlin.math.min
+
+class Solution {
+ private class Node {
+ var maxVal: Int = 0
+ var lazyDelta: Int = 0
+ }
+
+ private class SegmentTree(var n: Int) {
+ var tree: Array
+
+ init {
+ tree = Array(4 * this.n) { Node() }
+ }
+
+ fun push(nodeIdx: Int) {
+ if (tree[nodeIdx].lazyDelta != 0) {
+ tree[2 * nodeIdx].maxVal += tree[nodeIdx].lazyDelta
+ tree[2 * nodeIdx].lazyDelta += tree[nodeIdx].lazyDelta
+ tree[2 * nodeIdx + 1].maxVal += tree[nodeIdx].lazyDelta
+ tree[2 * nodeIdx + 1].lazyDelta += tree[nodeIdx].lazyDelta
+ tree[nodeIdx].lazyDelta = 0
+ }
+ }
+
+ fun update(queryStart: Int, queryEnd: Int, delta: Int) {
+ var queryStart = queryStart
+ var queryEnd = queryEnd
+ queryStart = max(1, queryStart)
+ queryEnd = min(n - 1, queryEnd)
+ if (queryStart > queryEnd) {
+ return
+ }
+ update(1, 1, n - 1, queryStart, queryEnd, delta)
+ }
+
+ fun update(
+ nodeIdx: Int,
+ start: Int,
+ end: Int,
+ queryStart: Int,
+ queryEnd: Int,
+ delta: Int,
+ ) {
+ if (start > end || start > queryEnd || end < queryStart) {
+ return
+ }
+ if (queryStart <= start && end <= queryEnd) {
+ tree[nodeIdx].maxVal += delta
+ tree[nodeIdx].lazyDelta += delta
+ return
+ }
+ push(nodeIdx)
+
+ val mid = (start + end) / 2
+ update(2 * nodeIdx, start, mid, queryStart, queryEnd, delta)
+ update(2 * nodeIdx + 1, mid + 1, end, queryStart, queryEnd, delta)
+ tree[nodeIdx].maxVal = max(tree[2 * nodeIdx].maxVal, tree[2 * nodeIdx + 1].maxVal)
+ }
+
+ fun queryMax(): Int {
+ if (n - 1 < 1) {
+ return 0
+ }
+ return tree[1].maxVal
+ }
+ }
+
+ fun maximumCount(nums: IntArray, queries: Array): IntArray {
+ val n = nums.size
+ val primeIndices: MutableMap> = HashMap()
+ for (i in 0.. TreeSet() }.add(i)
+ }
+ }
+ val segmentTree = SegmentTree(n)
+ for (entry in primeIndices.entries) {
+ val indices = entry.value
+ val first: Int = indices.first()!!
+ val last: Int = indices.last()!!
+ segmentTree.update(first + 1, last, 1)
+ }
+ val result = IntArray(queries.size)
+ for (q in queries.indices) {
+ val idx = queries[q][0]
+ val `val` = queries[q][1]
+ val oldVal = nums[idx]
+ if (isPrime[oldVal]) {
+ val indices: TreeSet = primeIndices[oldVal]!!
+ val oldFirst: Int = indices.first()!!
+ val oldLast: Int = indices.last()!!
+ indices.remove(idx)
+ if (indices.isEmpty()) {
+ primeIndices.remove(oldVal)
+ segmentTree.update(oldFirst + 1, oldLast, -1)
+ } else {
+ val newFirst: Int = indices.first()!!
+ val newLast: Int = indices.last()!!
+
+ if (idx == oldFirst && newFirst != oldFirst) {
+ segmentTree.update(oldFirst + 1, newFirst, -1)
+ }
+ if (idx == oldLast && newLast != oldLast) {
+ segmentTree.update(newLast + 1, oldLast, -1)
+ }
+ }
+ }
+ nums[idx] = `val`
+ if (isPrime[`val`]) {
+ val wasNewPrime = !primeIndices.containsKey(`val`)
+ val indices = primeIndices.computeIfAbsent(`val`) { _: Int -> TreeSet() }
+ val oldFirst: Int = (if (indices.isEmpty()) -1 else indices.first())!!
+ val oldLast: Int = (if (indices.isEmpty()) -1 else indices.last())!!
+ indices.add(idx)
+ val newFirst: Int = indices.first()!!
+ val newLast: Int = indices.last()!!
+ if (wasNewPrime) {
+ segmentTree.update(newFirst + 1, newLast, 1)
+ } else {
+ if (idx < oldFirst) {
+ segmentTree.update(newFirst + 1, oldFirst, 1)
+ }
+ if (idx > oldLast) {
+ segmentTree.update(oldLast + 1, newLast, 1)
+ }
+ }
+ }
+ val totalDistinctPrimesInCurrentNums = primeIndices.size
+ var maxIntersection = segmentTree.queryMax()
+ maxIntersection = max(0, maxIntersection)
+ result[q] = totalDistinctPrimesInCurrentNums + maxIntersection
+ }
+ return result
+ }
+
+ companion object {
+ private const val MAX_VAL = 100005
+ private val isPrime = BooleanArray(MAX_VAL)
+
+ init {
+ isPrime.fill(true)
+ isPrime[1] = false
+ isPrime[0] = false
+ var i = 2
+ while (i * i < MAX_VAL) {
+ if (isPrime[i]) {
+ var j = i * i
+ while (j < MAX_VAL) {
+ isPrime[j] = false
+ j += i
+ }
+ }
+ i++
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/readme.md b/src/main/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/readme.md
new file mode 100644
index 00000000..04262300
--- /dev/null
+++ b/src/main/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/readme.md
@@ -0,0 +1,47 @@
+3569\. Maximize Count of Distinct Primes After Split
+
+Hard
+
+You are given an integer array `nums` having length `n` and a 2D integer array `queries` where `queries[i] = [idx, val]`.
+
+For each query:
+
+1. Update `nums[idx] = val`.
+2. Choose an integer `k` with `1 <= k < n` to split the array into the non-empty prefix `nums[0..k-1]` and suffix `nums[k..n-1]` such that the sum of the counts of **distinct** prime values in each part is **maximum**.
+
+**Note:** The changes made to the array in one query persist into the next query.
+
+Return an array containing the result for each query, in the order they are given.
+
+**Example 1:**
+
+**Input:** nums = [2,1,3,1,2], queries = [[1,2],[3,3]]
+
+**Output:** [3,4]
+
+**Explanation:**
+
+* Initially `nums = [2, 1, 3, 1, 2]`.
+* After 1st query, `nums = [2, 2, 3, 1, 2]`. Split `nums` into `[2]` and `[2, 3, 1, 2]`. `[2]` consists of 1 distinct prime and `[2, 3, 1, 2]` consists of 2 distinct primes. Hence, the answer for this query is `1 + 2 = 3`.
+* After 2nd query, `nums = [2, 2, 3, 3, 2]`. Split `nums` into `[2, 2, 3]` and `[3, 2]` with an answer of `2 + 2 = 4`.
+* The output is `[3, 4]`.
+
+**Example 2:**
+
+**Input:** nums = [2,1,4], queries = [[0,1]]
+
+**Output:** [0]
+
+**Explanation:**
+
+* Initially `nums = [2, 1, 4]`.
+* After 1st query, `nums = [1, 1, 4]`. There are no prime numbers in `nums`, hence the answer for this query is 0.
+* The output is `[0]`.
+
+**Constraints:**
+
+* 2 <= n == nums.length <= 5 * 104
+* 1 <= queries.length <= 5 * 104
+* 1 <= nums[i] <= 105
+* `0 <= queries[i][0] < nums.length`
+* 1 <= queries[i][1] <= 105
\ No newline at end of file
diff --git a/src/test/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/SolutionTest.kt
new file mode 100644
index 00000000..1c823bd5
--- /dev/null
+++ b/src/test/kotlin/g3501_3600/s3566_partition_array_into_two_equal_product_subsets/SolutionTest.kt
@@ -0,0 +1,23 @@
+package g3501_3600.s3566_partition_array_into_two_equal_product_subsets
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun checkEqualPartitions() {
+ assertThat(
+ Solution().checkEqualPartitions(intArrayOf(3, 1, 6, 8, 4), 24L),
+ equalTo(true),
+ )
+ }
+
+ @Test
+ fun checkEqualPartitions2() {
+ assertThat(
+ Solution().checkEqualPartitions(intArrayOf(2, 5, 3, 7), 15L),
+ equalTo(false),
+ )
+ }
+}
diff --git a/src/test/kotlin/g3501_3600/s3567_minimum_absolute_difference_in_sliding_submatrix/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3567_minimum_absolute_difference_in_sliding_submatrix/SolutionTest.kt
new file mode 100644
index 00000000..4904fe59
--- /dev/null
+++ b/src/test/kotlin/g3501_3600/s3567_minimum_absolute_difference_in_sliding_submatrix/SolutionTest.kt
@@ -0,0 +1,31 @@
+package g3501_3600.s3567_minimum_absolute_difference_in_sliding_submatrix
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun minAbsDiff() {
+ assertThat>(
+ Solution().minAbsDiff(arrayOf(intArrayOf(1, 8), intArrayOf(3, -2)), 2),
+ equalTo>(arrayOf(intArrayOf(2))),
+ )
+ }
+
+ @Test
+ fun minAbsDiff2() {
+ assertThat>(
+ Solution().minAbsDiff(arrayOf(intArrayOf(3, -1)), 1),
+ equalTo>(arrayOf(intArrayOf(0, 0))),
+ )
+ }
+
+ @Test
+ fun minAbsDiff3() {
+ assertThat>(
+ Solution().minAbsDiff(arrayOf(intArrayOf(1, -2, 3), intArrayOf(2, 3, 5)), 2),
+ equalTo>(arrayOf(intArrayOf(1, 2))),
+ )
+ }
+}
diff --git a/src/test/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/SolutionTest.kt
new file mode 100644
index 00000000..a71a71fb
--- /dev/null
+++ b/src/test/kotlin/g3501_3600/s3568_minimum_moves_to_clean_the_classroom/SolutionTest.kt
@@ -0,0 +1,31 @@
+package g3501_3600.s3568_minimum_moves_to_clean_the_classroom
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun minMoves() {
+ assertThat(
+ Solution().minMoves(arrayOf("S.", "XL"), 2),
+ equalTo(2),
+ )
+ }
+
+ @Test
+ fun minMoves2() {
+ assertThat(
+ Solution().minMoves(arrayOf("LS", "RL"), 4),
+ equalTo(3),
+ )
+ }
+
+ @Test
+ fun minMoves3() {
+ assertThat(
+ Solution().minMoves(arrayOf("L.S", "RXL"), 3),
+ equalTo(-1),
+ )
+ }
+}
diff --git a/src/test/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/SolutionTest.kt
new file mode 100644
index 00000000..f2d87c9c
--- /dev/null
+++ b/src/test/kotlin/g3501_3600/s3569_maximize_count_of_distinct_primes_after_split/SolutionTest.kt
@@ -0,0 +1,40 @@
+package g3501_3600.s3569_maximize_count_of_distinct_primes_after_split
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun maximumCount() {
+ assertThat(
+ Solution()
+ .maximumCount(intArrayOf(2, 1, 3, 1, 2), arrayOf(intArrayOf(1, 2), intArrayOf(3, 3))),
+ equalTo(intArrayOf(3, 4)),
+ )
+ }
+
+ @Test
+ fun maximumCount2() {
+ assertThat(
+ Solution().maximumCount(intArrayOf(2, 1, 4), arrayOf(intArrayOf(0, 1))),
+ equalTo(intArrayOf(0)),
+ )
+ }
+
+ @Test
+ fun maximumCount3() {
+ assertThat(
+ Solution().maximumCount(intArrayOf(2, 34), arrayOf(intArrayOf(1, 2), intArrayOf(1, 3))),
+ equalTo(intArrayOf(2, 2)),
+ )
+ }
+
+ @Test
+ fun maximumCount4() {
+ assertThat(
+ Solution().maximumCount(intArrayOf(4, 2), arrayOf(intArrayOf(0, 2), intArrayOf(0, 2))),
+ equalTo(intArrayOf(2, 2)),
+ )
+ }
+}