Problem Statement
The land of a park AtCoder is an
N
×
N
N×N
N×N grid with east-west rows and north-south columns. The height of the square at the i-th row from the north and j-th column from the west is given as
A
i
,
j
A_{i,j}
Ai,j.
Takahashi, the manager, has decided to build a square pond occupying
K
×
K
K×K
K×K squares in this park.To do this, he wants to choose a square section of
K×K squares completely within the park whose median of the heights of the squares is the lowest. Find the median of the heights of the squares in such a section.
Here, the median of the heights of the squares in a K×K section is the height of the
(
⌊
K
2
2
⌋
+
1
)
(\lfloor \frac{K^2}{2}⌋+1)
(⌊2K2⌋+1)-th highest square among the
K
2
K^2
K2 squares in the section, where
⌊
x
⌋
⌊x⌋
⌊x⌋ is the greatest integer not exceeding
x
x
x.
Sample Input 1
3 2
1 7 0
5 8 11
10 4 2
Sample Output 1
4
Sample Input 2
3 3
1 2 3
4 5 6
7 8 9
Sample Output 2
5
二维前缀和+差分~
做个小转换,题目要求第
⌊
K
2
2
⌋
+
1
\lfloor \frac{K^2}{2}⌋+1
⌊2K2⌋+1 大,实际上就是求第
⌈
K
2
2
⌉
\lceil\frac{K^2}{2}\rceil
⌈2K2⌉ 小~
如果暴力的话时间复杂度
O
(
N
∗
N
∗
K
∗
K
)
O(N*N*K*K)
O(N∗N∗K∗K),显然不行,比赛中我还想了用数据结构存,但是复杂度也有
O
(
N
∗
N
∗
K
)
O(N*N*K)
O(N∗N∗K),还是会爆~
回到一开始,找一个
K
∗
K
K*K
K∗K 的矩阵第
⌈
K
2
2
⌉
\lceil\frac{K^2}{2}\rceil
⌈2K2⌉ 小,即这个矩阵中有
⌈
K
2
2
⌉
\lceil\frac{K^2}{2}\rceil
⌈2K2⌉ 个元素小于等于这个值,那么我们很容易想到二分,那怎么快速判断某个
K
∗
K
K*K
K∗K 矩阵中小于等于某个数的个数呢,离散化+二维前缀和即可,对二分的值
m
i
d
mid
mid,首先离散化,当
A
i
,
j
≤
m
i
d
A_{i,j}\leq mid
Ai,j≤mid,则置为
1
1
1,反之置为
0
0
0,然后通过二维前缀和可以快速计算出一个
K
∗
K
K*K
K∗K 矩阵中大于
m
i
d
mid
mid 的元素个数,暴力判断即可,复杂度
O
(
N
∗
N
∗
log
1
e
9
)
O(N*N*\log{1e9})
O(N∗N∗log1e9),AC代码如下:
n, k = map(int, input().split())
a = [[] for _ in range(805)]
b = [[0 for _ in range(805)] for _ in range(805)]
c = [[0 for _ in range(805)] for _ in range(805)]
for i in range(1, n + 1):
a[i] = list(map(int, input().split()))
# print(a[i])
l, r = 0, 10 ** 9
while l <= r:
mid = l + r >> 1
for i in range(1, n + 1):
for j in range(1, n + 1):
b[i][j] = 0 if a[i][j - 1] > mid else 1
for i in range(1, n + 1):
for j in range(1, n + 1):
c[i][j] = c[i - 1][j] + c[i][j - 1] - c[i - 1][j - 1] + b[i][j]
if c[n][n] < (k * k - 1) // 2 + 1:
l = mid + 1
continue
flag = 0
for i in range(k, n + 1):
for j in range(k, n + 1):
if c[i][j] - c[i - k][j] - c[i][j - k] + c[i - k][j - k] >= (k * k - 1) // 2 + 1:
flag = 1
break
if flag:
break
if flag:
r = mid - 1
else:
l = mid + 1
print(l)