LoginSignup
0
0

More than 1 year has passed since last update.

ABC212 C - Min Difference を解いてみた

Last updated at Posted at 2021-09-05

ABC212_C.png

2重 for で全探索してもよいが、計算量が 4*10^10 となり、TLE となる。
糸口を探すため、とりあえずサンプルを確認してみる。

abc212_SAMPLE.png

個人的に注目したのは入力例3
最小値を探すってことは、数列 A , 数列 B の中から値が近い要素の組み合わせを出せば良いんだよね?

ココから更に飛躍が入ります。
じゃあ、数列 A と数列 B を合体して sort したら A[n]=>B[m] or B[m]=>A[n] となる並びが必ずあり、
その中から差分が最小となる組み合わせを探せば良い
んだよね?

っと言うことで、これで行けました。

MinDifference_1.py
N,M = map(int,input().split())
A = list(map(int,input().split()))
B = list(map(int,input().split()))

A = list(set(A))#A の重複要素を排除
B = list(set(B))#B の重複要素を排除

#A,B を合体すると、ごちゃまぜで分からなくなるので、
#辞書で管理することにしました。
dicA = {}
dicB = {}

for i in range(len(A)):
    dicA[A[i]] = 1#冒頭で set() してるので重複要素なし、要素は必ず 1 つ
for i in range(len(B)):
    dicB[B[i]] = 1#冒頭で set() してるので重複要素なし、要素は必ず 1 つ

X = A + B # AとB を合体
X.sort()  # sort する

ans = float("inf") # 無限大より小さいものを for で探す

#辞書はリストに無い key の所在を尋ねると Error を返します。
#if X[i] in dicA としても良かったかもだが、dicA/dicB の要素数が計算量として上乗せされる。
#そのため 2*10^5 x 2*10^5 となる可能性があるので記述は避けた。
#代わりに try / except を使って計算量を抑えた.
for i in range(len(X)-1):#=> X を端から確認し、X[i],X[i+1] の差分をcheck。
    try:
        if dicA[X[i]] == 1 and dicB[X[i+1]] == 1:#辞書で X[i],X[i+1] がそれぞれ A,B であることを確認
            if abs(X[i]-X[i+1]) < ans:
                ans = abs(X[i]-X[i+1])
    except:#上記で Error で返したら、以下の処理に入る
        try:
            if dicB[X[i]]==1 and dicA[X[i+1]]==1:#辞書で X[i],X[i+1] がそれぞれ A,B であることを確認
                if abs(X[i] - X[i + 1]) < ans:
                    ans = abs(X[i] - X[i + 1])
        except:
            pass#上記でもダメなら pass。次の検証に向かう
print(ans)

きっと、もっと分かり易くて良い解法があるはず。

とりあえず、ほかの人の解法も読みながらイメージを積み上げてみようと思う。
感動したら、追記するかも。

理解があやふやかもしれないが、
上記の場合の計算量は O(N) だと思うが相違ないだろうか?
有識者のアドバイスがあれば助かります m(_ _)m

あれから

まだまだ少ないが色々解いて見識が広がったと信じ、再チャレンジ。
以下でも通った。

MinDifference_2.py
N,M = map(int,input().split())
A = list(map(int,input().split()))
B = list(map(int,input().split()))

dicA = {}
dicB = {}

for n in range(N):
    if A[n] not in dicA:
        dicA[A[n]] = 0
    dicA[A[n]] += 1

for m in range(M):
    if B[m] not in dicB:
        dicB[B[m]] = 0
    dicB[B[m]] += 1

X = A + B
X.sort()
score = float("inf")
for i in range(N+M-1):#max O(4*10**5)
    if X[i] in dicA and X[i+1] in dicB or X[i] in dicB and X[i+1] in dicA:
        score = min(score,abs(X[i]-X[i+1]))
print(score)

改善点

・A/B の重複削除の記述を排除
仮に重複があったともして前述にあるように O(4*10^5) なので計算量は問題にならないし、答えが変わることはない。
・try/except の記述を削除
辞書の in演算は O(1) なのでガンガン使うことで記述が計算量を気にせず、シンプルに書ける。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0