ムズイ _(:3」∠)_
K = int(input()) # 最大値の検索回数
N = 10000
x = int(pow(N, 0.5))
A = [int(input()) for _ in range(N)]
# ルートN に小数(端数)が出たら要素を 1 足して要素数を調整
# 今回は √10000 = 100 なので、無くても動く
x += int(N % x != 0)
srd_maxes = [max(A[i*x:(i+1)*x]) for i in range(x)]
for _ in range(K):
left, right = [[int(l_i)-1, int(r_i)-1] for l_i, r_i in [input().split()]][0]
max_ = A[left]
while left <= right:
if (left % x == 0) and (left + x-1 <= right):
max_ = max(max_, srd_maxes[left // x])
left += x # 次のバケットの先頭へ飛ぶ
else: # バケットの範囲外の時は、1つずつ調べていく
max_ = max(max_, A[left])
left += 1
print(max_)
# (left % x == 0) = 平方分割して区切ったブロックに到達し、
# そのブロックの最後の位置が right 以下
# (ブロック全ての要素を含む場合、平方分割して求めておいた値が使える)
私はこのメニューの中でこの問題がずっと解けませんでした。最後の問題の「点の幅」も。わかるようになった今でもプログラム化するのは難しいですね。何度も使って書き方を覚えるまではまたすぐに忘れてしまいます。なのでこのプログラムはメモしています。
前半は1つ前のプログラムと同じです。今回は文以下の部分が追加の問題となります。
入力 l_i
r_i
は 1 番目から数えていますので、これを要素番号に変換する為にここで 1 を引いておきます。
最大値を left
から順に探していきますので、max_
の初期値は A[left]
にしておきます。ここから A[right] までを調べていきます。while left <= right:
else: # バケットの範囲外の時は、1つずつ調べていく
max_ = max(max_, A[left])
left += 1
申し訳ない。先に else文のほうから説明します。
ここでは平方分割して予め最大値を求めておいたバケットの範囲外の所を調べています。単純に最初に取得した 数列A を使って1つずつ最大値を見つけて更新していきます。
A = [1, 2, 3, …, 98, 99, 100]
srd_maxes = [10, 20, …, 90, 100]
left = 7, right = 52 の時
8, 9, 10, {20, 30, 40, 50}, 51, 52, 53
初めは max_
には 8
が入っています。left += 1
しながら最大値を更新していきます。
10 に到達したら、この次は { } で囲まれている部分 「平方分割」 して予め最大値を求めておいた 数列 srd_maxes を使って最大値を見つけていきます。
while left <= right:
if (left % x == 0) and (left + x-1 <= right):
max_ = max(max_, srd_maxes[left // x])
left += x # 次のバケットの先頭へ飛ぶ
この部分が平方分割を利用した最大値の探索方法です。
A = [1, 2, 3, …, 98, 99, 100]
srd_maxes = [10, 20, …, 90, 100]
left = 7, right = 52 の時
8, 9, 10, {20, 30, 40, 50}, 51, 52, 53
現在 left = 10 (値 10 の次の所)
- left % x == 0
- left は 10、x は 100**0.5 = 10 なので、
10 % 10 = 0
- left + x-1 <= right
- 10 + 10 - 1 <= 53
どちらも True なので、srd_maxes
を使って最大値を求めます。
max_ = max(max_, srd_maxes[left // x])
srd_maxes = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
max_ = max(max_, srd_maxes[10 // 10])
↓
max_ = max(max_, srd_maxes[1])
↓
max_ = max(max_, 20)
left += 10
条件式が False になるまで、これを繰り返していきます。
max_ = max(max_, srd_maxes[20 // 10])
↓
max_ = max(max_, srd_maxes[2])
↓
max_ = max(max_, 30)
left += 10
(´ω`)
max_ = max(max_, srd_maxes[30 // 10])
↓
max_ = max(max_, srd_maxes[3])
↓
max_ = max(max_, 40)
left += 10
(゚з゚)
max_ = max(max_, srd_maxes[40 // 10])
↓
max_ = max(max_, srd_maxes[4])
↓
max_ = max(max_, 50)
left += 10
(*ノωノ)
ここで、left = 50 となります。
- left + x-1 <= right
- 50 + 10 - 1 <= 53 … False
この続きはまた else文のほうで処理します。
else: # バケットの範囲外の時は、1つずつ調べていく
max_ = max(max_, A[left])
left += 1
A = [1, 2, 3, …, 98, 99, 100]
srd_maxes = [10, 20, …, 90, 100]
left = 7, right = 52 の時
8, 9, 10, {20, 30, 40, 50}, 51, 52, 53
現在 left = 50 で、A[50] の値は 51
です。また left += 1
しながら最大値を更新していきます。そして while left <= right:
の評価が False となった時には max_
には指定された範囲の最大値が求められています。1 から順に並んでいるので当然 53
が入っているわけですけれども。😅