スパークリング黒ココア/ABC203まとめ

Created Sun, 10 Sep 2023 Modified Tue, 26 Sep 2023 09:13:30 +0000
1688 Words

A - Chinchirorin

https://atcoder.jp/contests/abc203/tasks/abc203_a

  • #XOR で解決するの賢いなぁ…
  • 言われた通り実装して、おわり。
l = list(map(int, input().split()))  
l.sort()  
if l[0] != l[1] and l[1] != l[2]:  
    print(0)  
elif l[0] == l[1]:  
    print(l[2])  
else:  
    print(l[0])

 B - AtCoder Condominium

https://atcoder.jp/contests/abc203/tasks/abc203_b

  • ループで愚直に答え足していったら、おわり
N, K = map(int, input().split())  
ans = 0  
for i in range(1, N + 1):  
    for j in range(1, K + 1):  
        ans += i * 100 + j  
print(ans)

C - Friends and Travel costs

https://atcoder.jp/contests/abc203/tasks/abc203_c

  • 数直線移動系 #シミュレーション
  • $10^{100}$まではどうあがいても無理だけど、村の数は$2\times 10^5$で済む
    • 村と村の間を$O(1)$で飛ばせたら勝ち
  • 1円で1個隣の村に移動できるので、手持ちのお金でどの村までいけるかわかる
    • いける村までの間に、お友達がいたら手持ちが増える
  • 後はしっかりシミュレーション
    • 村の順番、お友達を綺麗にまとめようね
from collections import defaultdict  
  
N, K = map(int, input().split())  
d = defaultdict(int)  
for i in range(N):  
    A, B = map(int, input().split())  
    d[A] += B
    
pos = 0  
ab_L = list(d.items())  
ab_L.sort()  
for node, val in ab_L:  
    if pos + K >= node:  
        cost = node - pos  
        K -= cost  
        K += val  
        pos = node  
  
    else:  
        pos += K  
        K = 0  
        break  
if K != 0:  
    pos += K  
print(pos)

D - Pond

https://atcoder.jp/contests/abc203/tasks/abc203_d

  • ◯◯の最小値(最大値)は、 #にぶたん を疑うこと #TIPS
  • 値決め打ちにぶたんを疑うに当たって、色々と考えてみる
    • $N\times N$のマス目から$K\times K$の区画を切り取った時、中央値を$x$以下にできる?
      • これは愚直なら$O(N^2 \times K^2)$でいけそう…
        • にぶたんコースなら、ここをどうにか削れたら…
    • 一部分の区画を見たいので、 #二次元累積和 でしばけそう
      • $N \times N$のマス目のうち、$x$以下のマスを1、$x$より大きいマスを0とする
      • この前処理を行ってから二次元累積和を作ると、「区画内の、$x$以下のマスの個数」が$O(1)$で出せる
        • $K\times K$の区画内で$x$以下のマスの個数が、半分以上→中央値を$x$以下にできる!
          • ここまでで、$N\times N$のマス目の前処理に$O(N^2)$、累積和作成で$O(N^2)$
          • $K\times K$の区画切り取りを累積和使って全探索して$O((N-K+1)^2)$
          • 合計$O(N^2)$でしばける
            • にぶたんで$O(log(max(A)))$でしばけるので、勝ち
  • 実装が面倒くさいので、色々関数切るのが良さげみありますね
N, K = map(int, input().split())  
  
base_L = []  
for i in range(N):  
    base_L.append(list(map(int, input().split())))  
  
# 元々の2次元配列から、「x未満なら1,そうじゃないなら0」の判定配列を作る関数
def make_2d_l(l, n):  
    ret_L = [[0] * len(l) for _ in range(len(l[0]))]  
    for i in range(len(l)):  
        for j in range(len(l[0])):  
            if l[i][j] <= n:  
                ret_L[i][j] = 1  
    return ret_L  
  
# 2次元配列を作る関数
def make_2d_accum(l):  
    ret_L = [[0] * (len(l[0]) + 1) for i in range(len(l) + 1)]  
  
    for i in range(N):  
        for j in range(len(l[0])):  
            ret_L[i + 1][j + 1] = ret_L[i][j + 1] + ret_L[i + 1][j] + l[i][j] - ret_L[i][j]  
  
    return ret_L  
  
# にぶたん判定用関数
def is_ok(arg):  
    l = make_2d_l(base_L, arg)  
    accum_l = make_2d_accum(l)  
  
    for i in range(N - K + 1):  
        for j in range(N - K + 1):  
            cnt = accum_l[i + K][j + K] - accum_l[i][j + K] - accum_l[i + K][j] + accum_l[i][j]  
            if cnt >= (K * K) // 2 + (K % 2):  
                return True  
    return False  

# にぶたんメイン部分
def meguru_bisect(ok, ng):  
    while abs(ok - ng) > 1:  
        mid = (ok + ng) // 2  
        if is_ok(mid):  
            ok = mid  
        else:  
            ng = mid  
    return ok  
  

ok = 10 ** 18  
ng = -1  
print(meguru_bisect(ok, ng))

 E - White Pawn

https://atcoder.jp/contests/abc203/tasks/abc203_e

  • 縦横$2\times 10^9 + 1$の大きさを持つチェス盤なのでちょっと全探索、愚直は無理
  • 条件の日本語難しいので、問題文を読む
    • 黒ポーンが無い限り、白ポーンはまっすぐ下にしか降りられない
    • 白ポーンの真下に黒ポーンがあったら、白ポーンは進めない
    • 斜め下に黒ポーンがあれば、白ポーンは黒ポーンを取れる
      • 黒ポーンのある行だけ考えたら良いかな…?
        • このあたりで、Cの村移動に似た #シミュレーション 系問題
  • 白ポーンの初期配置から、黒ポーンの存在する行毎にしっかりシミュレーションを行う
  • 白ポーンが動ける先と、白ポーンが進めなくなる先をしっかり考える
    • 一旦黒ポーン基準に考える
      • #主客転倒 ?になるのかな…?
      • この黒ポーンは踏めますか?
        • →Yes:以降、この列に白ポーンが存在できます
        • →No:この列に、現在白ポーンは存在しますか?
          • →Yes:以降、この列に白ポーンは存在できません
          • →No:もとからこの列に白ポーンは存在していません
  • 手間だけど、黒ポーンの存在する行ごとに、
    • 白ポーンが現在、存在できる列(pos)
    • 今後白ポーンが存在できるようになる列(add_L)
    • 今後白ポーンが存在できなくなる列(del_L)
      • を持って、ワンクッション置いて一括更新する形
    • どうせ追加→追加、追加→削除でも、$2\times M$なので…
from collections import defaultdict  
  
N, M = map(int, input().split())  
bk_pawn = defaultdict(set)  
for i in range(M):  
    X, Y = map(int, input().split())  
    bk_pawn[X].add(Y)  
  
bk_L = list(bk_pawn.items())  
bk_L.sort()  
pos = set([N])  
  
for k, bk_s in bk_L:  
  
    add_L = []  
    del_L = []  
  
    for bk in bk_s:  
        if bk + 1 not in pos and bk - 1 not in pos:  
            del_L.append(bk)  
        if bk - 1 in pos or bk + 1 in pos:  
            add_L.append(bk)  
    for add in add_L:  
        pos.add(add)  
    for dis in del_L:  
        pos.discard(dis)  
print(len(pos))