3548. Equal Sum Grid Partition II

This commit is contained in:
2026-03-26 13:33:38 +03:00
parent 3f3bc52106
commit 2cac465442
4 changed files with 294 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
public class Solution
{
struct SumInfo
{
public long Left;
public long Right;
public long Value;
// ключ - число, значение - индексы, где оно встречается
public Dictionary<long, SortedSet<int>> 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<long, SortedSet<int>>();
colSums[j].Nums ??= new Dictionary<long, SortedSet<int>>();
rowSums[i].Nums.TryAdd(num, new SortedSet<int>());
rowSums[i].Nums[num].Add(j);
colSums[j].Nums.TryAdd(num, new SortedSet<int>());
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;
}
/// <summary>
///
/// </summary>
/// <param name="target">Целевое число для поиска</param>
/// <param name="infos">Что перебирать</param>
/// <param name="idx">Индекс отсечения (для удаления справа строго больше, для удаления слева включительно)</param>
/// <param name="deleteAfterIdx">Удалять ли спарва от индекса</param>
/// <param name="firstAndLastOnly">Посмотреть только первый и последний SumInfo</param>
/// <param name="edgesOnly">В sumInfo брать только крайние элементы</param>
/// <param name="len">Количество чисел в SumInfo</param>
/// <returns></returns>
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;
}
}