diff --git a/src/main/kotlin/g3601_3700/s3673_find_zombie_sessions/readme.md b/src/main/kotlin/g3601_3700/s3673_find_zombie_sessions/readme.md
new file mode 100644
index 00000000..fabadfdb
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3673_find_zombie_sessions/readme.md
@@ -0,0 +1,105 @@
+3673\. Find Zombie Sessions
+
+Hard
+
+Table: `app_events`
+
+ +------------------+----------+
+ | Column Name | Type |
+ +------------------+----------+
+ | event_id | int |
+ | user_id | int |
+ | event_timestamp | datetime |
+ | event_type | varchar |
+ | session_id | varchar |
+ | event_value | int |
+ +------------------+----------+
+ event_id is the unique identifier for this table.
+ event_type can be app_open, click, scroll, purchase, or app_close.
+ session_id groups events within the same user session.
+ event_value represents: for purchase - amount in dollars, for scroll - pixels scrolled, for others - NULL.
+
+Write a solution to identify **zombie sessions, **sessions where users appear active but show abnormal behavior patterns. A session is considered a **zombie session** if it meets ALL the following criteria:
+
+* The session duration is **more than** `30` minutes.
+* Has **at least** `5` scroll events.
+* The **click-to-scroll ratio** is less than `0.20` .
+* **No purchases** were made during the session.
+
+Return _the result table ordered by_ `scroll_count` _in **descending** order, then by_ `session_id` _in **ascending** order_.
+
+The result format is in the following example.
+
+**Example:**
+
+**Input:**
+
+app\_events table:
+
+ +----------+---------+---------------------+------------+------------+-------------+
+ | event_id | user_id | event_timestamp | event_type | session_id | event_value |
+ +----------+---------+---------------------+------------+------------+-------------+
+ | 1 | 201 | 2024-03-01 10:00:00 | app_open | S001 | NULL |
+ | 2 | 201 | 2024-03-01 10:05:00 | scroll | S001 | 500 |
+ | 3 | 201 | 2024-03-01 10:10:00 | scroll | S001 | 750 |
+ | 4 | 201 | 2024-03-01 10:15:00 | scroll | S001 | 600 |
+ | 5 | 201 | 2024-03-01 10:20:00 | scroll | S001 | 800 |
+ | 6 | 201 | 2024-03-01 10:25:00 | scroll | S001 | 550 |
+ | 7 | 201 | 2024-03-01 10:30:00 | scroll | S001 | 900 |
+ | 8 | 201 | 2024-03-01 10:35:00 | app_close | S001 | NULL |
+ | 9 | 202 | 2024-03-01 11:00:00 | app_open | S002 | NULL |
+ | 10 | 202 | 2024-03-01 11:02:00 | click | S002 | NULL |
+ | 11 | 202 | 2024-03-01 11:05:00 | scroll | S002 | 400 |
+ | 12 | 202 | 2024-03-01 11:08:00 | click | S002 | NULL |
+ | 13 | 202 | 2024-03-01 11:10:00 | scroll | S002 | 350 |
+ | 14 | 202 | 2024-03-01 11:15:00 | purchase | S002 | 50 |
+ | 15 | 202 | 2024-03-01 11:20:00 | app_close | S002 | NULL |
+ | 16 | 203 | 2024-03-01 12:00:00 | app_open | S003 | NULL |
+ | 17 | 203 | 2024-03-01 12:10:00 | scroll | S003 | 1000 |
+ | 18 | 203 | 2024-03-01 12:20:00 | scroll | S003 | 1200 |
+ | 19 | 203 | 2024-03-01 12:25:00 | click | S003 | NULL |
+ | 20 | 203 | 2024-03-01 12:30:00 | scroll | S003 | 800 |
+ | 21 | 203 | 2024-03-01 12:40:00 | scroll | S003 | 900 |
+ | 22 | 203 | 2024-03-01 12:50:00 | scroll | S003 | 1100 |
+ | 23 | 203 | 2024-03-01 13:00:00 | app_close | S003 | NULL |
+ | 24 | 204 | 2024-03-01 14:00:00 | app_open | S004 | NULL |
+ | 25 | 204 | 2024-03-01 14:05:00 | scroll | S004 | 600 |
+ | 26 | 204 | 2024-03-01 14:08:00 | scroll | S004 | 700 |
+ | 27 | 204 | 2024-03-01 14:10:00 | click | S004 | NULL |
+ | 28 | 204 | 2024-03-01 14:12:00 | app_close | S004 | NULL |
+ +----------+---------+---------------------+------------+------------+-------------+
+
+**Output:**
+
+ +------------+---------+--------------------------+--------------+
+ | session_id | user_id | session_duration_minutes | scroll_count |
+ +------------+---------+--------------------------+--------------+
+ | S001 | 201 | 35 | 6 |
+ +------------+---------+--------------------------+--------------+
+
+**Explanation:**
+
+* **Session S001 (User 201)**:
+ * Duration: 10:00:00 to 10:35:00 = 35 minutes (more than 30)
+ * Scroll events: 6 (at least 5)
+ * Click events: 0
+ * Click-to-scroll ratio: 0/6 = 0.00 (less than 0.20)
+ * Purchases: 0 (no purchases)
+ * S001 is a zombie session (meets all criteria)
+* **Session S002 (User 202)**:
+ * Duration: 11:00:00 to 11:20:00 = 20 minutes (less than 30)
+ * Has a purchase event
+ * S002 is not a zombie session
+* **Session S003 (User 203)**:
+ * Duration: 12:00:00 to 13:00:00 = 60 minutes (more than 30)
+ * Scroll events: 5 (at least 5)
+ * Click events: 1
+ * Click-to-scroll ratio: 1/5 = 0.20 (not less than 0.20)
+ * Purchases: 0 (no purchases)
+ * S003 is not a zombie session (click-to-scroll ratio equals 0.20, needs to be less)
+* **Session S004 (User 204)**:
+ * Duration: 14:00:00 to 14:12:00 = 12 minutes (less than 30)
+ * Scroll events: 2 (less than 5)
+ * S004 is not a zombie session
+
+The result table is ordered by scroll\_count in descending order, then by session\_id in ascending order.
\ No newline at end of file
diff --git a/src/main/kotlin/g3601_3700/s3673_find_zombie_sessions/script.sql b/src/main/kotlin/g3601_3700/s3673_find_zombie_sessions/script.sql
new file mode 100644
index 00000000..87f37171
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3673_find_zombie_sessions/script.sql
@@ -0,0 +1,23 @@
+# Write your MySQL query statement below
+# #Hard #Database #2025_09_07_Time_278_ms_(100.00%)_Space_0.0_MB_(100.00%)
+SELECT
+ session_id,
+ user_id,
+ TIMESTAMPDIFF(MINUTE, MIN(event_timestamp), MAX(event_timestamp)) AS session_duration_minutes,
+ SUM(CASE WHEN event_type = 'scroll' THEN 1 ELSE 0 END) AS scroll_count -- NOSONAR
+FROM
+ app_events
+GROUP BY
+ session_id,
+ user_id
+HAVING
+ TIMESTAMPDIFF(MINUTE, MIN(event_timestamp), MAX(event_timestamp)) > 30
+ AND SUM(CASE WHEN event_type = 'scroll' THEN 1 ELSE 0 END) > 4 -- NOSONAR
+ AND (
+ CAST(SUM(CASE WHEN event_type = 'click' THEN 1 ELSE 0 END) AS DOUBLE) /
+ NULLIF(SUM(CASE WHEN event_type = 'scroll' THEN 1 ELSE 0 END), 0) -- NOSONAR
+ ) < 0.2
+ AND SUM(CASE WHEN event_type = 'purchase' THEN 1 ELSE 0 END) = 0
+ORDER BY
+ scroll_count DESC,
+ session_id ASC;
diff --git a/src/main/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/Solution.kt b/src/main/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/Solution.kt
new file mode 100644
index 00000000..8e39e311
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/Solution.kt
@@ -0,0 +1,14 @@
+package g3601_3700.s3674_minimum_operations_to_equalize_array
+
+// #Easy #Weekly_Contest_466 #2025_09_07_Time_1_ms_(100.00%)_Space_43.60_MB_(100.00%)
+
+class Solution {
+ fun minOperations(nums: IntArray): Int {
+ for (num in nums) {
+ if (num != nums[0]) {
+ return 1
+ }
+ }
+ return 0
+ }
+}
diff --git a/src/main/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/readme.md b/src/main/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/readme.md
new file mode 100644
index 00000000..ccdd1973
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/readme.md
@@ -0,0 +1,36 @@
+3674\. Minimum Operations to Equalize Array
+
+Easy
+
+You are given an integer array `nums` of length `n`.
+
+In one operation, choose any subarray `nums[l...r]` (`0 <= l <= r < n`) and **replace** each element in that subarray with the **bitwise AND** of all elements.
+
+Return the **minimum** number of operations required to make all elements of `nums` equal.
+
+A **subarray** is a contiguous **non-empty** sequence of elements within an array.
+
+**Example 1:**
+
+**Input:** nums = [1,2]
+
+**Output:** 1
+
+**Explanation:**
+
+Choose `nums[0...1]`: `(1 AND 2) = 0`, so the array becomes `[0, 0]` and all elements are equal in 1 operation.
+
+**Example 2:**
+
+**Input:** nums = [5,5,5]
+
+**Output:** 0
+
+**Explanation:**
+
+`nums` is `[5, 5, 5]` which already has all elements equal, so 0 operations are required.
+
+**Constraints:**
+
+* `1 <= n == nums.length <= 100`
+* 1 <= nums[i] <= 105
\ No newline at end of file
diff --git a/src/main/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/Solution.kt b/src/main/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/Solution.kt
new file mode 100644
index 00000000..b5415b58
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/Solution.kt
@@ -0,0 +1,23 @@
+package g3601_3700.s3675_minimum_operations_to_transform_string
+
+// #Medium #Weekly_Contest_466 #2025_09_14_Time_6_ms_(97.92%)_Space_57.75_MB_(43.75%)
+
+class Solution {
+ fun minOperations(s: String): Int {
+ val n = s.length
+ var ans = 0
+ for (i in 0.. ans) {
+ ans = ops
+ }
+ if (ops == 25) {
+ break
+ }
+ }
+ }
+ return ans
+ }
+}
diff --git a/src/main/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/readme.md b/src/main/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/readme.md
new file mode 100644
index 00000000..7ce2dabe
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/readme.md
@@ -0,0 +1,41 @@
+3675\. Minimum Operations to Transform String
+
+Medium
+
+You are given a string `s` consisting only of lowercase English letters.
+
+You can perform the following operation any number of times (including zero):
+
+* Choose any character `c` in the string and replace **every** occurrence of `c` with the **next** lowercase letter in the English alphabet.
+
+
+Return the **minimum** number of operations required to transform `s` into a string consisting of **only** `'a'` characters.
+
+**Note:** Consider the alphabet as circular, thus `'a'` comes after `'z'`.
+
+**Example 1:**
+
+**Input:** s = "yz"
+
+**Output:** 2
+
+**Explanation:**
+
+* Change `'y'` to `'z'` to get `"zz"`.
+* Change `'z'` to `'a'` to get `"aa"`.
+* Thus, the answer is 2.
+
+**Example 2:**
+
+**Input:** s = "a"
+
+**Output:** 0
+
+**Explanation:**
+
+* The string `"a"` only consists of `'a'` characters. Thus, the answer is 0.
+
+**Constraints:**
+
+* 1 <= s.length <= 5 * 105
+* `s` consists only of lowercase English letters.
\ No newline at end of file
diff --git a/src/main/kotlin/g3601_3700/s3676_count_bowl_subarrays/Solution.kt b/src/main/kotlin/g3601_3700/s3676_count_bowl_subarrays/Solution.kt
new file mode 100644
index 00000000..5debc1bc
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3676_count_bowl_subarrays/Solution.kt
@@ -0,0 +1,25 @@
+package g3601_3700.s3676_count_bowl_subarrays
+
+// #Medium #Weekly_Contest_466 #2025_09_14_Time_3_ms_(100.00%)_Space_79.40_MB_(50.00%)
+
+class Solution {
+ fun bowlSubarrays(nums: IntArray): Long {
+ val n = nums.size
+ var res = n
+ var pre = 0
+ for (a in nums) {
+ if (a > pre) {
+ res--
+ pre = a
+ }
+ }
+ pre = 0
+ for (i in n - 1 downTo 0) {
+ if (nums[i] > pre) {
+ res--
+ pre = nums[i]
+ }
+ }
+ return res + 1L
+ }
+}
diff --git a/src/main/kotlin/g3601_3700/s3676_count_bowl_subarrays/readme.md b/src/main/kotlin/g3601_3700/s3676_count_bowl_subarrays/readme.md
new file mode 100644
index 00000000..99488aa3
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3676_count_bowl_subarrays/readme.md
@@ -0,0 +1,51 @@
+3676\. Count Bowl Subarrays
+
+Medium
+
+You are given an integer array `nums` with **distinct** elements.
+
+A subarray `nums[l...r]` of `nums` is called a **bowl** if:
+
+* The subarray has length at least 3. That is, `r - l + 1 >= 3`.
+* The **minimum** of its two ends is **strictly greater** than the **maximum** of all elements in between. That is, `min(nums[l], nums[r]) > max(nums[l + 1], ..., nums[r - 1])`.
+
+Return the number of **bowl** subarrays in `nums`.
+
+**Example 1:**
+
+**Input:** nums = [2,5,3,1,4]
+
+**Output:** 2
+
+**Explanation:**
+
+The bowl subarrays are `[3, 1, 4]` and `[5, 3, 1, 4]`.
+
+* `[3, 1, 4]` is a bowl because `min(3, 4) = 3 > max(1) = 1`.
+* `[5, 3, 1, 4]` is a bowl because `min(5, 4) = 4 > max(3, 1) = 3`.
+
+**Example 2:**
+
+**Input:** nums = [5,1,2,3,4]
+
+**Output:** 3
+
+**Explanation:**
+
+The bowl subarrays are `[5, 1, 2]`, `[5, 1, 2, 3]` and `[5, 1, 2, 3, 4]`.
+
+**Example 3:**
+
+**Input:** nums = [1000000000,999999999,999999998]
+
+**Output:** 0
+
+**Explanation:**
+
+No subarray is a bowl.
+
+**Constraints:**
+
+* 3 <= nums.length <= 105
+* 1 <= nums[i] <= 109
+* `nums` consists of distinct elements.
\ No newline at end of file
diff --git a/src/main/kotlin/g3601_3700/s3677_count_binary_palindromic_numbers/Solution.kt b/src/main/kotlin/g3601_3700/s3677_count_binary_palindromic_numbers/Solution.kt
new file mode 100644
index 00000000..394d2bee
--- /dev/null
+++ b/src/main/kotlin/g3601_3700/s3677_count_binary_palindromic_numbers/Solution.kt
@@ -0,0 +1,38 @@
+package g3601_3700.s3677_count_binary_palindromic_numbers
+
+// #Hard #Weekly_Contest_466 #2025_09_07_Time_1_ms_(100.00%)_Space_41.19_MB_(100.00%)
+
+class Solution {
+ private fun makePalin(left: Long, odd: Boolean): Long {
+ var left = left
+ var ans = left
+ if (odd) {
+ left = left shr 1
+ }
+ while (left > 0) {
+ ans = (ans shl 1) or (left and 1L)
+ left = left shr 1
+ }
+ return ans
+ }
+
+ fun countBinaryPalindromes(n: Long): Int {
+ if (n == 0L) {
+ return 1
+ }
+ val len = 64 - java.lang.Long.numberOfLeadingZeros(n)
+ var count: Long = 1
+ for (i in 1..0 <= n <= 1015
\ No newline at end of file
diff --git a/src/test/kotlin/g3601_3700/s3673_find_zombie_sessions/MysqlTest.kt b/src/test/kotlin/g3601_3700/s3673_find_zombie_sessions/MysqlTest.kt
new file mode 100644
index 00000000..a72e25c2
--- /dev/null
+++ b/src/test/kotlin/g3601_3700/s3673_find_zombie_sessions/MysqlTest.kt
@@ -0,0 +1,91 @@
+package g3601_3700.s3673_find_zombie_sessions
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+import org.zapodot.junit.db.annotations.EmbeddedDatabase
+import org.zapodot.junit.db.annotations.EmbeddedDatabaseTest
+import org.zapodot.junit.db.common.CompatibilityMode
+import java.io.BufferedReader
+import java.io.FileNotFoundException
+import java.io.FileReader
+import java.sql.SQLException
+import java.util.stream.Collectors
+import javax.sql.DataSource
+
+@EmbeddedDatabaseTest(
+ compatibilityMode = CompatibilityMode.MySQL,
+ initialSqls = [
+ (
+ "CREATE TABLE app_events (" +
+ " event_id INT PRIMARY KEY," +
+ " user_id INT NOT NULL," +
+ " event_timestamp TIMESTAMP NOT NULL," +
+ " event_type VARCHAR(50) NOT NULL," +
+ " session_id VARCHAR(50) NOT NULL," +
+ " event_value INT" +
+ ");" +
+ "INSERT INTO app_events (event_id, user_id, event_timestamp, " +
+ "event_type, session_id, event_value) VALUES" +
+ "(1, 201, '2024-03-01 10:00:00', 'app_open', 'S001', NULL)," +
+ "(2, 201, '2024-03-01 10:05:00', 'scroll', 'S001', 500)," +
+ "(3, 201, '2024-03-01 10:10:00', 'scroll', 'S001', 750)," +
+ "(4, 201, '2024-03-01 10:15:00', 'scroll', 'S001', 600)," +
+ "(5, 201, '2024-03-01 10:20:00', 'scroll', 'S001', 800)," +
+ "(6, 201, '2024-03-01 10:25:00', 'scroll', 'S001', 550)," +
+ "(7, 201, '2024-03-01 10:30:00', 'scroll', 'S001', 900)," +
+ "(8, 201, '2024-03-01 10:35:00', 'app_close', 'S001', NULL)," +
+ "(9, 202, '2024-03-01 11:00:00', 'app_open', 'S002', NULL)," +
+ "(10, 202, '2024-03-01 11:02:00', 'click', 'S002', NULL)," +
+ "(11, 202, '2024-03-01 11:05:00', 'scroll', 'S002', 400)," +
+ "(12, 202, '2024-03-01 11:08:00', 'click', 'S002', NULL)," +
+ "(13, 202, '2024-03-01 11:10:00', 'scroll', 'S002', 350)," +
+ "(14, 202, '2024-03-01 11:15:00', 'purchase', 'S002', 50)," +
+ "(15, 202, '2024-03-01 11:20:00', 'app_close','S002', NULL)," +
+ "(16, 203, '2024-03-01 12:00:00', 'app_open', 'S003', NULL)," +
+ "(17, 203, '2024-03-01 12:10:00', 'scroll', 'S003', 1000)," +
+ "(18, 203, '2024-03-01 12:20:00', 'scroll', 'S003', 1200)," +
+ "(19, 203, '2024-03-01 12:25:00', 'click', 'S003', NULL)," +
+ "(20, 203, '2024-03-01 12:30:00', 'scroll', 'S003', 800)," +
+ "(21, 203, '2024-03-01 12:40:00', 'scroll', 'S003', 900)," +
+ "(22, 203, '2024-03-01 12:50:00', 'scroll', 'S003', 1100)," +
+ "(23, 203, '2024-03-01 13:00:00', 'app_close','S003', NULL)," +
+ "(24, 204, '2024-03-01 14:00:00', 'app_open', 'S004', NULL)," +
+ "(25, 204, '2024-03-01 14:05:00', 'scroll', 'S004', 600)," +
+ "(26, 204, '2024-03-01 14:08:00', 'scroll', 'S004', 700)," +
+ "(27, 204, '2024-03-01 14:10:00', 'click', 'S004', NULL)," +
+ "(28, 204, '2024-03-01 14:12:00', 'app_close','S004', NULL);"
+ ),
+ ],
+)
+internal class MysqlTest {
+ @Test
+ @Throws(SQLException::class, FileNotFoundException::class)
+ fun testScript(@EmbeddedDatabase dataSource: DataSource) {
+ dataSource.connection.use { connection ->
+ connection.createStatement().use { statement ->
+ statement.executeQuery(
+ BufferedReader(
+ FileReader(
+ (
+ "src/main/kotlin/g3601_3700/" +
+ "s3673_find_zombie_sessions/" +
+ "script.sql"
+ ),
+ ),
+ )
+ .lines()
+ .collect(Collectors.joining("\n"))
+ .replace("#.*?\\r?\\n".toRegex(), ""),
+ ).use { resultSet ->
+ assertThat(resultSet.next(), equalTo(true))
+ assertThat(resultSet.getNString(1), equalTo("S001"))
+ assertThat(resultSet.getNString(2), equalTo("201"))
+ assertThat(resultSet.getNString(3), equalTo("35"))
+ assertThat(resultSet.getNString(4), equalTo("6"))
+ assertThat(resultSet.next(), equalTo(false))
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/SolutionTest.kt b/src/test/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/SolutionTest.kt
new file mode 100644
index 00000000..15e53a37
--- /dev/null
+++ b/src/test/kotlin/g3601_3700/s3674_minimum_operations_to_equalize_array/SolutionTest.kt
@@ -0,0 +1,17 @@
+package g3601_3700.s3674_minimum_operations_to_equalize_array
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun minOperations() {
+ assertThat(Solution().minOperations(intArrayOf(1, 2)), equalTo(1))
+ }
+
+ @Test
+ fun minOperations2() {
+ assertThat(Solution().minOperations(intArrayOf(5, 5, 5)), equalTo(0))
+ }
+}
diff --git a/src/test/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/SolutionTest.kt b/src/test/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/SolutionTest.kt
new file mode 100644
index 00000000..ecbe4eb3
--- /dev/null
+++ b/src/test/kotlin/g3601_3700/s3675_minimum_operations_to_transform_string/SolutionTest.kt
@@ -0,0 +1,17 @@
+package g3601_3700.s3675_minimum_operations_to_transform_string
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun minOperations() {
+ assertThat(Solution().minOperations("yz"), equalTo(2))
+ }
+
+ @Test
+ fun minOperations2() {
+ assertThat(Solution().minOperations("a"), equalTo(0))
+ }
+}
diff --git a/src/test/kotlin/g3601_3700/s3676_count_bowl_subarrays/SolutionTest.kt b/src/test/kotlin/g3601_3700/s3676_count_bowl_subarrays/SolutionTest.kt
new file mode 100644
index 00000000..8cd38488
--- /dev/null
+++ b/src/test/kotlin/g3601_3700/s3676_count_bowl_subarrays/SolutionTest.kt
@@ -0,0 +1,31 @@
+package g3601_3700.s3676_count_bowl_subarrays
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun bowlSubarrays() {
+ assertThat(
+ Solution().bowlSubarrays(intArrayOf(2, 5, 3, 1, 4)),
+ equalTo(2L),
+ )
+ }
+
+ @Test
+ fun bowlSubarrays2() {
+ assertThat(
+ Solution().bowlSubarrays(intArrayOf(5, 1, 2, 3, 4)),
+ equalTo(3L),
+ )
+ }
+
+ @Test
+ fun bowlSubarrays3() {
+ assertThat(
+ Solution().bowlSubarrays(intArrayOf(1000000000, 999999999, 999999998)),
+ equalTo(0L),
+ )
+ }
+}
diff --git a/src/test/kotlin/g3601_3700/s3677_count_binary_palindromic_numbers/SolutionTest.kt b/src/test/kotlin/g3601_3700/s3677_count_binary_palindromic_numbers/SolutionTest.kt
new file mode 100644
index 00000000..ac5d7d4e
--- /dev/null
+++ b/src/test/kotlin/g3601_3700/s3677_count_binary_palindromic_numbers/SolutionTest.kt
@@ -0,0 +1,58 @@
+package g3601_3700.s3677_count_binary_palindromic_numbers
+
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.jupiter.api.Test
+
+internal class SolutionTest {
+ @Test
+ fun countBinaryPalindromes() {
+ assertThat(Solution().countBinaryPalindromes(9L), equalTo(6))
+ }
+
+ @Test
+ fun countBinaryPalindromes2() {
+ assertThat(Solution().countBinaryPalindromes(9L), equalTo(6))
+ }
+
+ @Test
+ fun countBinaryPalindromes3() {
+ // Branch: n == 0 → returns 1 immediately
+ assertThat(Solution().countBinaryPalindromes(0), equalTo(1))
+ }
+
+ @Test
+ fun countBinaryPalindromes4() {
+ // n = 1 ("1") → palindrome
+ // Expected palindromes: 1 (0) + 1 (1) = 2
+ assertThat(Solution().countBinaryPalindromes(1), equalTo(2))
+ }
+
+ @Test
+ fun countBinaryPalindromes5() {
+ // n = 6 ("110"), length = 3 (odd)
+ // Palindromes up to 6: 0,1,3,5
+ assertThat(Solution().countBinaryPalindromes(6), equalTo(4))
+ }
+
+ @Test
+ fun countBinaryPalindromes6() {
+ // n = 9 ("1001"), palindrome itself
+ // Palindromes up to 9: 0,1,3,5,7,9
+ assertThat(Solution().countBinaryPalindromes(9), equalTo(6))
+ }
+
+ @Test
+ fun countBinaryPalindromes7() {
+ // n = 10 ("1010") → next palindrome = 9 (smaller) → branch where palin <= n
+ // Palindromes up to 10: 0,1,3,5,7,9
+ assertThat(Solution().countBinaryPalindromes(10), equalTo(6))
+ }
+
+ @Test
+ fun countBinaryPalindromes8() {
+ // 1023 = "1111111111"
+ val n = (1L shl 10) - 1
+ assertThat(Solution().countBinaryPalindromes(n), equalTo(63))
+ }
+}