diff --git a/3548. Equal Sum Grid Partition II/3548. Equal Sum Grid Partition II.csproj b/3548. Equal Sum Grid Partition II/3548. Equal Sum Grid Partition II.csproj
new file mode 100644
index 0000000..f026990
--- /dev/null
+++ b/3548. Equal Sum Grid Partition II/3548. Equal Sum Grid Partition II.csproj
@@ -0,0 +1,11 @@
+
+
+
+ Exe
+ net10.0
+ _3548._Equal_Sum_Grid_Partition_II
+ enable
+ enable
+
+
+
diff --git a/3548. Equal Sum Grid Partition II/Program.cs b/3548. Equal Sum Grid Partition II/Program.cs
new file mode 100644
index 0000000..5afba82
--- /dev/null
+++ b/3548. Equal Sum Grid Partition II/Program.cs
@@ -0,0 +1,139 @@
+var sol = new Solution();
+
+var cases = new (int[][] grid, bool expected, string name)[]
+{
+ (
+ new[]
+ {
+ new[] { 1, 4 },
+ new[] { 2, 3 }
+ },
+ true,
+ "Example 1"
+ ),
+ (
+ new[]
+ {
+ new[] { 1, 2 },
+ new[] { 3, 4 }
+ },
+ true,
+ "Example 2"
+ ),
+ (
+ new[]
+ {
+ new[] { 1, 2, 4 },
+ new[] { 2, 3, 5 }
+ },
+ false,
+ "Example 3"
+ ),
+ (
+ new[]
+ {
+ new[] { 4, 1, 8 },
+ new[] { 3, 2, 6 }
+ },
+ false,
+ "Example 4"
+ ),
+ (
+ new[]
+ {
+ new[] { 5, 5, 6, 2, 2, 2 }
+ },
+ true,
+ "Example 5"
+ ),
+ (
+ new[]
+ {
+ new[] { 100000 },
+ new[] { 86218 },
+ new[] { 100000 }
+ },
+ true,
+ "Example 6"
+ ),
+ (
+ new[]
+ {
+ new[] { 1, 2, 4 },
+ new[] { 1, 6, 6 },
+ new[] { 5, 6, 7 }
+ },
+ true,
+ "Example 7"
+ ),
+ (
+ new[]
+ {
+ new[] { 1, 2, 1, 1, 1 },
+ new[] { 1, 1, 1, 2, 1 }
+ },
+ true,
+ "Example 8"
+ ),
+ (
+ new[]
+ {
+ new[] { 1, 1 },
+ new[] { 2, 1 },
+ new[] { 1, 1 },
+ new[] { 1, 2 },
+ new[] { 1, 1 }
+ },
+ true,
+ "Example 9"
+ ),
+ (
+ new[]
+ {
+ new[] { 10, 5, 4, 5 }
+ },
+ false,
+ "Example 10"
+ ),
+ (
+ new[]
+ {
+ new[] { 1, 1 },
+ new[] { 2, 1 },
+ new[] { 4, 3 }
+ },
+ false,
+ "Example 11"
+ ),
+ (
+ new[]
+ {
+ new[] { 4 },
+ new[] { 3 },
+ new[] { 4 },
+ new[] { 4 },
+ new[] { 4 }
+ },
+ false,
+ "Example 12"
+ ),
+ (
+ new[]
+ {
+ new[] { 100000 },
+ new[] { 100000 },
+ new[] { 100000 },
+ new[] { 100000 },
+ new[] { 1 }
+ },
+ true,
+ "Example 13"
+ ),
+
+};
+
+foreach (var (grid, expected, name) in cases)
+{
+ var actual = sol.CanPartitionGrid(grid);
+ Console.WriteLine($"{name}: {actual} (expected: {expected})");
+}
diff --git a/3548. Equal Sum Grid Partition II/Solution.cs b/3548. Equal Sum Grid Partition II/Solution.cs
new file mode 100644
index 0000000..be0a639
--- /dev/null
+++ b/3548. Equal Sum Grid Partition II/Solution.cs
@@ -0,0 +1,130 @@
+public class Solution
+{
+ struct SumInfo
+ {
+ public long Left;
+ public long Right;
+ public long Value;
+ // ключ - число, значение - индексы, где оно встречается
+ public Dictionary> Nums;
+ }
+
+ public bool CanPartitionGrid(int[][] grid)
+ {
+ var height = grid.Length;
+ var width = grid[0].Length;
+
+ var colSums = new SumInfo[width];
+ var rowSums = new SumInfo[height];
+ for (var i = 0; i < height; i++)
+ {
+ for (var j = 0; j < width; j++)
+ {
+ var num = grid[i][j];
+ colSums[j].Value += num;
+ rowSums[i].Value += num;
+ rowSums[i].Nums ??= new Dictionary>();
+ colSums[j].Nums ??= new Dictionary>();
+
+ rowSums[i].Nums.TryAdd(num, new SortedSet());
+ rowSums[i].Nums[num].Add(j);
+
+ colSums[j].Nums.TryAdd(num, new SortedSet());
+ colSums[j].Nums[num].Add(i);
+ }
+ rowSums[i].Left = rowSums[i].Value;
+ if (i > 0)
+ rowSums[i].Left += rowSums[i - 1].Left;
+ }
+ for (var i = height - 1; i >= 0; i--)
+ {
+ rowSums[i].Right = rowSums[i].Value;
+ if (i < height - 1)
+ rowSums[i].Right += rowSums[i + 1].Right;
+ }
+ for (var j = 0; j < width; j++)
+ {
+ colSums[j].Left = colSums[j].Value;
+ if (j > 0)
+ colSums[j].Left += colSums[j - 1].Left;
+ }
+ for (var j = width - 1; j >= 0; j--)
+ {
+ colSums[j].Right = colSums[j].Value;
+ if (j < width - 1)
+ colSums[j].Right += colSums[j + 1].Right;
+ }
+ var answer = false;
+ for (var i = 0; i < rowSums.Length - 1 && !answer; i++)
+ {
+ var row = rowSums[i];
+ var nextRow = rowSums[i + 1];
+ var diff = Math.Abs(row.Left - nextRow.Right);
+
+ var edgesOnly = colSums.Length == 1;
+ var colLen = height;
+ if (diff == 0 ||
+ (row.Left < nextRow.Right && CanDelete(diff, colSums, i, true, i + 1 == rowSums.Length - 1, edgesOnly, colLen)) ||
+ (row.Left > nextRow.Right && CanDelete(diff, colSums, i, false, i == 0, edgesOnly, colLen)))
+ answer |= true;
+ }
+ for (var j = 0; j < colSums.Length - 1 && !answer; j++)
+ {
+ var col = colSums[j];
+ var nextCol = colSums[j + 1];
+ var diff = Math.Abs(col.Left - nextCol.Right);
+ // тут проход по колонкам, значит поиск элемента для удаления надо выполнять по строкам
+ // если j == 0 и отрезаем в левой части, то надо смотреть только первую и последнюю строку
+ // если j+1 == colSums.Len-1 и отрезаем в правой части, то надо смотреть только первую и последнюю строку
+ var edgesOnly = rowSums.Length == 1;
+ var rowLen = width;
+ if (diff == 0 ||
+ (col.Left < nextCol.Right && CanDelete(diff, rowSums, j, true, j + 1 == colSums.Length - 1, edgesOnly, rowLen)) ||
+ (col.Left > nextCol.Right && CanDelete(diff, rowSums, j, false, j == 0, edgesOnly, rowLen)))
+ answer |= true;
+ }
+ return answer;
+ }
+
+ ///
+ ///
+ ///
+ /// Целевое число для поиска
+ /// Что перебирать
+ /// Индекс отсечения (для удаления справа строго больше, для удаления слева включительно)
+ /// Удалять ли спарва от индекса
+ /// Посмотреть только первый и последний SumInfo
+ /// В sumInfo брать только крайние элементы
+ /// Количество чисел в SumInfo
+ ///
+ private static bool CanDelete(long target, SumInfo[] infos, int idx, bool deleteAfterIdx, bool firstAndLastOnly, bool edgesOnly, int len)
+ {
+ for (var i = 0; i < infos.Length; i++)
+ {
+ var nums = infos[i].Nums;
+
+ if (nums.TryGetValue(target, out var indexes))
+ {
+ var before = false;
+ var after = false;
+ if (edgesOnly)
+ {
+ before = indexes.Contains(0) || indexes.Contains(idx);
+ after = indexes.Contains(len - 1) || indexes.Contains(idx+1);
+ }
+ else
+ {
+ before = indexes.GetViewBetween(int.MinValue, idx).Count > 0;
+ after = indexes.GetViewBetween(idx + 1, int.MaxValue).Count > 0;
+ }
+ if ((before && !deleteAfterIdx) || (after && deleteAfterIdx))
+ return true;
+ }
+
+ // если только границы, перейти сразу к последнему элементу
+ if (firstAndLastOnly && i == 0)
+ i = Math.Max(i, infos.Length - 2);
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/Leetcode.sln b/Leetcode.sln
index 25d7a63..0d16be9 100644
--- a/Leetcode.sln
+++ b/Leetcode.sln
@@ -197,6 +197,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "114. Flatten Binary Tree to
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "30. Substring with Concatenation of All Words", "30. Substring with Concatenation of All Words\30. Substring with Concatenation of All Words.csproj", "{DC410457-B769-4597-857D-5AAD2BDBAAC3}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "3548. Equal Sum Grid Partition II", "3548. Equal Sum Grid Partition II\3548. Equal Sum Grid Partition II.csproj", "{D4C2B514-1A13-495A-8627-8B40AD8B2770}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1371,6 +1373,18 @@ Global
{DC410457-B769-4597-857D-5AAD2BDBAAC3}.Release|x64.Build.0 = Release|Any CPU
{DC410457-B769-4597-857D-5AAD2BDBAAC3}.Release|x86.ActiveCfg = Release|Any CPU
{DC410457-B769-4597-857D-5AAD2BDBAAC3}.Release|x86.Build.0 = Release|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Debug|x64.Build.0 = Debug|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Debug|x86.Build.0 = Debug|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Release|x64.ActiveCfg = Release|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Release|x64.Build.0 = Release|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Release|x86.ActiveCfg = Release|Any CPU
+ {D4C2B514-1A13-495A-8627-8B40AD8B2770}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE