二维前缀和+滑动窗口优化
2025-11-21 20:15:27
发布于:江苏
8阅读
0回复
0点赞
这个题目数据范围是,就算先进行二维前缀和优化,然后枚举左上角和右下角坐标,时间复杂度为,极有可能超时,
但是实际上可以通过,就需要进行优化
步骤 1:前缀和预处理(二维转一维辅助)
首先计算矩阵的二维前缀和,目的是快速计算任意子矩形的元素和。
前缀和数组 定义:表示以 为左上角、为右下角的子矩形的元素和(注意:代码中直接在原矩阵上修改存储前缀和,空间优化)。
前缀和公式:(容斥原理,避免重复计算)。
前缀和在这里不进行赘述
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]; // 前缀和
步骤 2:枚举行范围(压缩维度 )
枚举所有可能的 “上下行边界” 组合 :
对于每个固定的行范围 ,问题转化为:在这 行中,找到一个列范围 ,使得该列范围内的元素和 ,且矩形面积 最小。
从第 行到第 行,第 列到第第 列 的面积就是
步骤 3:滑动窗口找最小列范围(一维优化 )
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++) // 枚举从第i行到第j行
{
int l = 0, sum = 0; // l:左边界,sum:从第i行到第j行的第1列的和
for (int r = 1; r <= m; r++) // 枚举右边界
{
sum = a[j][r] - a[j][l] - a[i - 1][r] + a[i - 1][l]; // 当前矩形的和
int tmp = (j - i + 1) * (r - l); // 当前矩形的面积
if (sum >= k)
ans = min(ans, tmp); // 更新最小面积
while (a[j][r] - a[j][l + 1] - a[i - 1][r] + a[i - 1][l + 1] >= k)
{
sum = a[j][r] - a[j][l + 1] - a[i - 1][r] + a[i - 1][l + 1]; // 更新当前矩形的和
l++; // 左边界右移
ans = min(ans, (j - i + 1) * (r - l)); // 更新最小面积
}
}
}
}
对于固定的行范围 ,用双指针(滑动窗口) 遍历列:
右指针 从 到 逐步扩展(扩大窗口右边界)。
左指针 初始为 (不包含第 列的数据 ),当窗口内的和 时,尝试右移 缩小窗口,直到和 ,期间不断更新最小面积。
窗口和计算:利用前缀和快速得到 行、 列的子矩形和:。

最终代码(时间复杂度)
#include <bits/stdc++.h>
#define N 105
using namespace std;
int n, m, ans = 100 * 100, k;
int a[N][N];
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%1d", &a[i][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]; // 前缀和
if (a[n][m] < k) // 特判
{
printf("0");
return 0;
}
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++) // 枚举从第i行到第j行
{
int l = 0, sum = 0; // l:左边界,sum:从第i行到第j行的第1列的和
for (int r = 1; r <= m; r++) // 枚举右边界
{
sum = a[j][r] - a[j][l] - a[i - 1][r] + a[i - 1][l]; // 当前矩形的和
int tmp = (j - i + 1) * (r - l); // 当前矩形的面积
if (sum >= k)
ans = min(ans, tmp); // 更新最小面积
while (a[j][r] - a[j][l + 1] - a[i - 1][r] + a[i - 1][l + 1] >= k)
{
sum = a[j][r] - a[j][l + 1] - a[i - 1][r] + a[i - 1][l + 1]; // 更新当前矩形的和
l++; // 左边界右移
ans = min(ans, (j - i + 1) * (r - l)); // 更新最小面积
}
}
}
printf("%d", ans);
return 0;
}
这里空空如也




有帮助,赞一个