AtCoder Beginner Contest 203(Sponsored by Panasonic)D.Pond

50 篇文章 1 订阅
36 篇文章 0 订阅

题目链接

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(NNKK),显然不行,比赛中我还想了用数据结构存,但是复杂度也有 O ( N ∗ N ∗ K ) O(N*N*K) O(NNK),还是会爆~
回到一开始,找一个 K ∗ K K*K KK 的矩阵第 ⌈ K 2 2 ⌉ \lceil\frac{K^2}{2}\rceil 2K2 小,即这个矩阵中有 ⌈ K 2 2 ⌉ \lceil\frac{K^2}{2}\rceil 2K2 个元素小于等于这个值,那么我们很容易想到二分,那怎么快速判断某个 K ∗ K K*K KK 矩阵中小于等于某个数的个数呢,离散化+二维前缀和即可,对二分的值 m i d mid mid,首先离散化,当 A i , j ≤ m i d A_{i,j}\leq mid Ai,jmid,则置为 1 1 1,反之置为 0 0 0,然后通过二维前缀和可以快速计算出一个 K ∗ K K*K KK 矩阵中大于 m i d mid mid 的元素个数,暴力判断即可,复杂度 O ( N ∗ N ∗ log ⁡ 1 e 9 ) O(N*N*\log{1e9}) O(NNlog1e9),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)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旺 崽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值