一篇文章学会滑动窗口(单调队列) 超详细解释_滑动时间窗口的单调性-CSDN博客
AcWing 4964. 二维的单调队列(对一维再求一次就可) - AcWing
使用二维单调队列,先求出每行中长度为b的子列表的最大最小值,转化为最大、最小值矩阵(max, min),然后对这两个矩阵再次利用单调队列求出每列中长度为a的最大、最小值,更新max,min矩阵,最后求出所有max[i][j] * min[i][j]之和对998244353取模即可得到答案
from collections import deque
n, m, a, b = list(map(int, input().split()))
matrix = []
for i in range(n):
lst = list(map(int, input().split()))
matrix.append(lst)
def max_min_row(arr, func):
ans = []
q = deque()
for i, v in enumerate(arr, 1):
while q and q[0][0] <= i - b: # 若队列第一个数为前一个窗口最左端的数,窗口移动后,该数不再出现在窗口中,则应删除
q.popleft()
while q and func(v, q[-1][1]): # 若要增加的数v比单调递增队列中最后一个数小(或者比单调递减队列中最后一个数大)时,最后一个数必然不可能是最小(大)值,则将其从队列中删除
q.pop()
q.append((i, v))
if i >= b:
ans.append(q[0][1])
return ans
def max_min_col(arr, index, func):
ans = []
q = deque()
for i in range(0, n):
v = arr[i][index]
while q and q[0][0] <= i - a:
q.popleft()
while q and func(v, q[-1][1]):
q.pop()
q.append((i, v))
if i + 1 >= a:
ans.append(q[0][1])
return ans
max_row, min_row, max_col, min_col = [], [], [], []
for i in range(0, n):
max_row.append(max_min_row(matrix[i], lambda x, y : x > y))
min_row.append(max_min_row(matrix[i], lambda x, y : x < y))
for i in range(0, m - b + 1):
max_col.append(max_min_col(max_row, i, lambda x, y : x > y))
min_col.append(max_min_col(min_row, i, lambda x, y : x < y))
res = 0
mod = 998244353
for i in range(0, m - b + 1):
for j in range(0, n - a + 1):
res = (res + max_col[i][j] * min_col[i][j]) % mod
print(res)