小明有一个大小为
N
×
M
N × M
N×M 的矩阵,可以理解为一个
N
N
N 行
M
M
M 列的二维数组。我们定义一个矩阵
m
m
m 的稳定度
f
(
m
)
f(m)
f(m) 为
f
(
m
)
=
m
a
x
(
m
)
−
m
i
n
(
m
)
f(m) = max(m) − min(m)
f(m)=max(m)−min(m),其中
m
a
x
(
m
)
max(m)
max(m)
表示矩阵
m
m
m 中的最大值,
m
i
n
(
m
)
min(m)
min(m) 表示矩阵
m
m
m 中的最小值。现在小明想要从这个矩阵中找到一个稳定度不大于
l
i
m
i
t
limit
limit 的子矩阵,同时他还希望这个子矩阵的面积越大越好(面积可以理解为矩阵中元素个数)。
子矩阵定义如下:从原矩阵中选择一组连续的行和一组连续的列,这些行列交点上的元素组成的矩阵即为一个子矩阵。
第一行输入两个整数
N
,
M
N,M
N,M,表示矩阵的大小。
接下来
N
N
N 行,每行输入
M
M
M 个整数,表示这个矩阵。
最后一行输入一个整数
l
i
m
i
t
limit
limit,表示限制。
输出一个整数,分别表示小明选择的子矩阵的最大面积。
3 4
2 0 7 9
0 6 9 7
8 4 6 4
8
6
1
≤
n
≤
80
,
1
≤
m
≤
1
0
5
,
1
≤
n
∗
m
≤
1
0
5
1\leq n \leq80,1 \leq m \leq10^5,1 \leq n*m \leq10^5
1≤n≤80,1≤m≤105,1≤n∗m≤105
0
≤
0 \leq
0≤ 矩阵元素值,
l
i
m
i
t
≤
1
0
5
limit \leq 10^5
limit≤105




1,所以这其实就是一个一维数组滑动窗口求最值问题,属于是单调队列的模板使用,求出每个长度为
m
i
d
mid
mid的窗口的最大值
m
a
x
max
max和最小值
m
i
n
min
min,只要有一个窗口符合
m
a
x
−
m
i
n
<
=
l
i
m
i
t
max-min<=limit
max−min<=limit我们都返回true,否则返回false。Java
import java.io.*;
import java.util.*;
public class Main {
//max[k][i][j]表示第k列中[i,j]之间的最大值
static int[][][] max;
static int[][][] min;
static int n, m, limit,ans;
static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
String[] s=br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
max=new int[m+1][n+1][n+1];
min=new int[m+1][n+1][n+1];
for (int i = 1; i <= n; i++) {
s=br.readLine().split(" ");
for (int j = 1; j <= m; j++) {
max[j][i][i] = min[j][i][i] = Integer.parseInt(s[j-1]);
}
}
limit = Integer.parseInt(br.readLine());
//预处理 复杂度 n^2*m
for (int k = 1; k <= m; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
max[k][i][j] = Math.max(max[k][i][j - 1], max[k][j][j]);
min[k][i][j] = Math.min(min[k][i][j - 1], min[k][j][j]);
}
}
}
for (int x1 = 1; x1 <= n; x1++) {
for (int x2 = x1; x2 <= n; x2++) {
int l = 1, r = m;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(x1, x2, mid)) l = mid;
else r = mid - 1;
}
if (check(x1,x2,r)) ans=Math.max(ans,(x2-x1+1)*r);
}
}
out.println(ans);
out.flush();
}
//k是窗口大小
static boolean check(int x1, int x2, int k) {
Deque<Integer> qmax = new ArrayDeque<>();
Deque<Integer> qmin = new ArrayDeque<>();
for (int i = 1; i <= m; i++) {
//处理最小
if (!qmin.isEmpty() && qmin.peekFirst() < i - k + 1) qmin.pollFirst();
while (!qmin.isEmpty() && min[qmin.peekLast()][x1][x2] > min[i][x1][x2]) qmin.pollLast();
qmin.offerLast(i);
//处理最大
if (!qmax.isEmpty() && qmax.peekFirst() < i - k + 1) qmax.pollFirst();
while (!qmax.isEmpty() && max[qmax.peekLast()][x1][x2] < max[i][x1][x2]) qmax.pollLast();
qmax.offerLast(i);
//说明窗口为k
if (i >= k && max[qmax.peekFirst()][x1][x2] - min[qmin.peekFirst()][x1][x2] <= limit) return true;
}
return false;
}
}
C++
#include
using namespace std;
const int N = 81, M = 100010;
int n, m, lim, ans;
bool check(vector<vector<vector<int>>> &minv, vector<vector<vector<int>>> &maxv, int r1, int r2, int k) {
deque<int> qmax, qmin;
for (int i = 1; i <= m; ++i) {
if (!qmin.empty() && i - qmin.front() + 1 > k) qmin.pop_front();
while (!qmin.empty() && minv[qmin.back()][r1][r2] > minv[i][r1][r2]) qmin.pop_back();
qmin.push_back(i);
if (!qmax.empty() && i - qmax.front() + 1 > k) qmax.pop_front();
while (!qmax.empty() && maxv[qmax.back()][r1][r2] < maxv[i][r1][r2]) qmax.pop_back();
qmax.push_back(i);
if (i >= k && maxv[qmax.front()][r1][r2] - minv[qmin.front()][r1][r2] <= lim) return true;
}
return false;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
vector<vector<vector<int>>> minv(m + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 0)));
vector<vector<vector<int>>> maxv(m + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 0)));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> minv[j][i][i], maxv[j][i][i] = minv[j][i][i];
cin >> lim;
for (int k = 1; k <= m; ++k)
for (int i = 1; i <= n; ++i)
for (int j = i + 1; j <= n; ++j) {
maxv[k][i][j] = max(maxv[k][i][j - 1], maxv[k][j][j]);
minv[k][i][j] = min(minv[k][i][j - 1], minv[k][j][j]);
}
for (int r1 = 1; r1 <= n; ++r1) {
for (int r2 = r1; r2 <= n; ++r2) {
int l = 0, r = m;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(minv, maxv, r1, r2, mid)) l = mid;
else r = mid - 1;
}
ans = max(ans, (r2 - r1 + 1) * l);
}
}
cout << ans;
}