第145回【Python】点の幅
現在取り組んでいるのは、paiza ラーニング問題集「クエリメニュー」になります。
はじめに
猫とキャンプと野球観戦と AWS が大好きな旦那、LeoSaki です。モフモフしたい。
Python をゼロから勉強してみよう、のコーナー 145 回目です。
以前に比べて、1 問にかかる時間が伸びていることが分かります。それでも、まずは自力で解くことが大前提だと思っているので、腰を据えて挑戦しています。自ずと勉強時間が伸びています。楽しいからいっか!
それでは、今日も頑張ってみようと思います。
点の幅
テストの返却中に暇だった paiza 君は、また 2 人で遊ぶゲームを思いつきました。
「2 人はそれぞれ生徒番号 1 〜 N の全校生徒 N 人の中から生徒番号が連続するように好きな人数の生徒を選ぶ。その選んだ生徒達の得点の幅が大きい方、すなわちその生徒たちの (最高点 – 最低点) の値が大きい方が勝ち、同じだったら引き分け!」
「ただし、このルールだと人を多く選ぶ方が有利になってしまうから、選べる生徒の数はお互い N/2 人以下ね!」
また審判を任されたあなたは、全ての生徒の得点を記録しておくことで、選んだ生徒たちの最小・最大の生徒番号を確認するだけで、その生徒たちの中の (最高点 – 最低点) の値をすぐに求めることができることに気付きました。
学校の生徒数 N と試合の数 K , 各生徒の得点 S_1 … S_N と、
i 番目の試合で対戦した A と B の 2 人が選んだ生徒の最小の生徒番号と最大の生徒番号が与えられるので、各試合のジャッジをしてください。
N K
S_1
...
S_N
A_{l_1} A_{r_1} B_{l_1} B_{r_1}
...
A_{l_K} A_{r_K} B_{l_K} B_{r_K}
・1 行目では、生徒数 N とおこなわれる試合数 K が与えられます。
・続く N 行のうち、i 行目では、生徒番号 i の生徒のテストの得点 S_i が与えられます。
・続く K 行のうち、i 行目では、i 試合目のプレイヤー A が選んだ生徒のうち、最小の生徒番号と最大の生徒番号 A_{l_i} , A_{r_i} とプレイヤー B が選んだ生徒のうち、最小の生徒番号と最大の生徒番号 B_{l_i} , B_{r_i} が与えられます。
期待する出力
ans_1
...
ans_K
・i 行目に i 試合目の結果を出力してください。
A の勝ちの場合は 'A’, B の勝ちの場合は 'B’ , 引き分けの場合は 'DRAW’ と出力してください。
・また、出力の末尾には改行を入れてください。
すべてのテストケースにおいて、以下の条件をみたします。
・1 ≦ N ≦ 10,000
・N は平方数である(ある整数 x > 0 を用いて N = x^2 と表すことができる)
・1 ≦ K ≦ 100,000
・0 ≦ S_i ≦ 100,000 (1 ≦ i ≦ N)
・1 ≦ Al_i ≦ Ar_i ≦ N (1 ≦ i ≦ K)
・1 ≦ Bl_i ≦ Br_i ≦ N (1 ≦ i ≦ K)
・各ゲームにおいて、プレイヤーの選ぶ生徒の数は N/2 以下であることが保証されている。
入力例
4 2
1
3
2
4
1 2 2 3
1 2 3 4
出力例
A
DRAW
審判を任されてしまった LeoSaki(旦那)は、全員のテストの点数を教えてもらわないといけないらしいです。そんなまさか、教えてくれるのか?
Python
def comparison(X,max_range,min_range,sqrt,left,right):
max_now = 0
min_now = 100000
div = left // sqrt
while left <= right:
if left % sqrt == 0 and left + sqrt - 1 <= right:
max_now = max(max_now,max_range[div])
min_now = min(min_now,min_range[div])
left += sqrt
else:
max_now = max(max_now,X[left])
min_now = min(min_now,X[left])
left += 1
return max_now,min_now
N,K = map(int,input().split())
A = [int(input()) for _ in range(N)]
sqrt = int(pow(N,0.5))
if sqrt ** 2 < N:
sqrt += 1
temp = N // sqrt
max_range = [None] * (temp)
min_range = [None] * (temp)
for i in range(temp):
s,e = sqrt * i,sqrt * (i+1)
max_range[i] = max(A[s:e])
min_range[i] = min(A[s:e])
for _ in range(K):
al,ar,bl,br = map(lambda x:int(x)-1,input().split())
a_max_now,a_min_now = comparison(A,max_range,min_range,sqrt,al,ar)
b_max_now,b_min_now = comparison(A,max_range,min_range,sqrt,bl,br)
a_score = a_max_now - a_min_now
b_score = b_max_now - b_min_now
if a_score > b_score:
print('A')
elif a_score < b_score:
print('B')
else:
print('DRAW')
VBA
Sub query_primer__range_of_score()
NK = Split(Cells(1, 1), " ")
N = Val(NK(0))
k = Val(NK(1))
Dim a()
a = Range(Cells(2, 1), Cells(N + 1, 1))
sqrt = Application.WorksheetFunction.RoundUp(Sqr(N), 0)
div = Application.WorksheetFunction.RoundUp(N / sqrt, 0)
Dim range_max() As Long
Dim range_min() As Long
Dim temp_max() As Long
Dim temp_min() As Long
ReDim range_max(1 To div)
ReDim range_min(1 To div)
ReDim temp_max(1 To sqrt)
ReDim temp_min(1 To sqrt)
For i = 1 To div
s = sqrt * (i - 1) + 1
e = sqrt * i
ad = 1
For j = s To e
If j > N Then
temp_max(ad) = 0
temp_min(ad) = 100000
Else
temp_max(ad) = a(j, 1)
temp_min(ad) = a(j, 1)
End If
ad = ad + 1
Next
range_max(i) = Application.WorksheetFunction.Max(temp_max)
range_min(i) = Application.WorksheetFunction.Min(temp_min)
Next
For i = 1 To k
in_ = Split(Cells(i + N + 1, 1), " ")
a_left = Val(in_(0))
a_right = Val(in_(1))
b_left = Val(in_(2))
b_right = Val(in_(3))
a_now = comparison(a, range_max, range_min, sqrt, a_left, a_right)
b_now = comparison(a, range_max, range_min, sqrt, b_left, b_right)
a_score = a_now(0) - a_now(1)
b_score = b_now(0) - b_now(1)
If a_score > b_score Then
Debug.Print "A"
ElseIf a_score < b_score Then
Debug.Print "B"
Else
Debug.Print "DRAW"
End If
Next
End Sub
Private Function comparison(X, range_max, range_min, sqrt, left_, right_)
max_now = 0
min_now = 100000
div = Int(left_ / sqrt) + 1
Do While left_ <= right_
If left_ Mod sqrt = 1 And left_ + sqrt - 1 <= right_ Then
max_now = Application.WorksheetFunction.Max(max_now, range_max(div))
min_now = Application.WorksheetFunction.Min(min_now, range_min(div))
left_ = left_ + sqrt
Else
max_now = Application.WorksheetFunction.Max(max_now, X(left_, 1))
min_now = Application.WorksheetFunction.Min(min_now, X(left_, 1))
left_ = left_ + 1
End If
Loop
comparison = Array(max_now, min_now)
End Function
いつもの如く、境界値データテストでは(最初から Debug.Print 無し)、約 128 秒。
最後に
Python でも、7 秒程度かかっていた模様なので、最初から Debug.Print 無しで回してみましたが、2 分ちょっとなら悪くないスコアな気がしました。こういうやり方もあるんだなぁ、と大変勉強になりました。
これで「クエリメニュー」が終了です。最後の方は B ランク問題や A ランク問題ばかりになって、なかなか面白かったです。B ランク以上の問題に挑戦していたのに、次は「B ランクレベルアップメニュー」に挑戦してみたいと思います。
引き続き、よろしくお願いいたします!
ディスカッション
コメント一覧
まだ、コメントがありません