黒ココアさんのメモ置き場

メモを置いたり置かなかったり

ABC344 B - Delimiter

atcoder.jp

問題

  • $N$個の整数$A$が、1行に1つずつ与えられるよ
  • $N$は入力では与えられないよ
  • $A_{N}=0$だよ!
  • Aを逆順に出力してね!

成約

  • $1 \leq N \leq 100$
  • $1 \leq A_{i} \leq 10^{9} (1 \leq i \leq N-1)$
  • $A_{N} = 0$

思考

  • 最後の入力(=0)までずっと受け取って、最後の入力が確認出来たら、出力すれば良いね

コード

L = []
while True:
    A = int(input())
    L.append(A)
    if A == 0:
        break

for a in L[::-1]:
    print(a)

ABC344 A - Spoiler

atcoder.jp

問題

  • 文字列$S$が与えられます
    • 英小文字と、ちょうど2つの"|"が含まれるよ
  • 2つの"|"と、その間にある文字を削除した文字列を教えてね

成約

  • $2 \leq |S|\leq 100$

思考1

  • 文字列を、"|"で分割して、先頭のパーツと末尾のパーツだけ取り出せたら良いね!
    • split()で文字列を分割すると良いね

コード

S = input()
L = S.split("|")
print(L[0] + L[-1])

ABC343 F - Second Largest Query

atcoder.jp

問題

  • 長さNの数列Aが与えられるよ
  • Q個のクエリを捌いてね
    • タイプ1:$A_{i}$をxに変更
    • タイプ2:区間$l,r$の中で、2番目に大きい値の個数を出力

成約

  • $1 \leq N,Q \leq 2 \times 10^{5}$

思考

  • こねこねしてダメ元でSQLite投げてみたりしたけどダメでした(それはそう)
  • セグ木のモノイドをイジイジする問題!教育的!
  • (区間のうち1番大きい値,←の個数,区間のうち2番目に大きい値,←の個数)を乗せたら後は木が勝手にしてくれる
  • セグ木って、すごい

コード

import sys
from atcoder.segtree import SegTree
input = sys.stdin.buffer.readline

N,Q = map(int,input().split())
A_L = list(map(int, input().split()))

e = (0,0,0,0)

def op(a,b):
    a_num1,a_cnt1,a_num2,a_cnt2 = a
    b_num1,b_cnt1,b_num2,b_cnt2 = b
    if a_num1 == b_num1:
        ret_num1 = a_num1
        ret_cnt1 = a_cnt1 + b_cnt1
        if a_num2 == b_num2:
            ret_num2 = a_num2
            ret_cnt2 = a_cnt2 + b_cnt2
        elif a_num2 > b_num2:
            ret_num2 = a_num2
            ret_cnt2 = a_cnt2
        else:
            ret_num2 = b_num2
            ret_cnt2 = b_cnt2
    elif a_num1 > b_num1:
        ret_num1 = a_num1
        ret_cnt1 = a_cnt1
        if a_num2 == b_num1:
            ret_num2 = a_num2
            ret_cnt2 = a_cnt2 + b_cnt1
        elif a_num2 > b_num1:
            ret_num2 = a_num2
            ret_cnt2 = a_cnt2
        else:
            ret_num2 = b_num1
            ret_cnt2 = b_cnt1
    else:
        ret_num1 = b_num1
        ret_cnt1 = b_cnt1
        if a_num1 == b_num2:
            ret_num2 = a_num1
            ret_cnt2 = a_cnt1 + b_cnt2
        elif a_num1 > b_num2:
            ret_num2 = a_num1
            ret_cnt2 = a_cnt1
        else:
            ret_num2 = b_num2
            ret_cnt2 = b_cnt2
    return ret_num1, ret_cnt1, ret_num2, ret_cnt2


seg = SegTree(op, e, [(a,1,0,0) for a in A_L])

for i in range(Q):
    query = list(map(int, input().split()))
    if query[0] == 1:
        p,x = query[1:]
        p -= 1
        seg.set(p,(x,1,0,0))
    else:
        l,r = query[1:]
        l-=1
        print(seg.prod(l,r)[3])

ABC343 E - 7x7x7

atcoder.jp

問題

  • 1辺7の立方体を、座標空間上に3つ配置するよ
  • V1,V2,V3が与えられるよ
    • 3つの立方体のうち、丁度1つに含まれる領域の体積がV1
    • 3つの立方体のうち、丁度2つに含まれる領域の体積がV2
    • 3つの立方体のうち、丁度3つに含まれる領域の体積がV3
  • になるような立方体の配置を教えてね。無理なら無理って言ってね

成約

  • $1 \leq V_1,V_2,V_3 \leq 3 \times 7^{3}$

思考

  • 3つの衝突判定面倒くさそうだなぁ、と思って割と早めに投げ捨てた…終了後、解説を読んで冷静に考えるととてももったいないことをした…
  • まず、1辺7の立方体3つで、与えられた体積が実現できるの?で枝刈り
    • 黒ココアさんの手癖。何も考えずに刈る。よくなさそう。
  • 3つ置くことを考える時、1個は中心で固定しちゃって問題なさそう(直感)
    • 残り2つが、固定した1つとの相対的な位置で話が進みそう(直感)
    • 立方体2つを設置する座標を全探索しそう
  • また、めっちゃ遠くに立方体を設置しても、共通領域が存在しないベタ付けしても、話はあんまり変わらなさそう
    • 各方向に対して、-7~7までの座標で良さそう
      • 0~7だとダメ
      • 実は-1~7で良い、らしい(解説)
  • 固定した立方体をAとした時、以下の2種類の数値を考える
    • AとBの共通部分
    • BとCの共通部分
    • CとAの共通部分
    • AとBとCの共通部分
  • ベン図を書いてみて、上記4つが分かれば、V1も計算できるね
    • $O(1)$で出せるハズ
  • 後は、全体の計算量の見積もり
    • -7~7の15座標が、3方向
    • その立方体を2つ置くので、$O(15^{6}) \fallingdotseq 10^{7}$で間に合うとの話
  • 実装面倒くさい問題だったけど、話は割とシンプルだった、とかいう…

コード

import sys
input = sys.stdin.buffer.readline

V = list(map(int,input().split()))

if 7*7*7*3 != V[0] + 2*V[1] + 3*V[2]:
    print("No")
    exit()

ax,ay,az = 0,0,0

def calc_v3(bx,by,bz,cx,cy,cz):
    xl = sorted([ax,bx,cx])
    x = xl[0] - xl[2] + 7
    if x <= 0:return 0
    yl = sorted([ay,by,cy])
    y = yl[0] - yl[2] + 7
    if y <= 0:return 0
    zl = sorted([az,bz,cz])
    z = zl[0] - zl[2] + 7
    if z <= 0:return 0
    return x*y*z

def calc_v2(ax,ay,az,bx,by,bz):
    x = min(ax,bx) - max(ax,bx) + 7
    if x <= 0:return 0
    y = min(ay,by) - max(ay,by) + 7
    if y <= 0:return 0
    z = min(az,bz) - max(az,bz) + 7
    if z <= 0:return 0
    return x*y*z

for bx in range(-7,8):
    for by in range(-7,8):
        for bz in range(-7,8):
            for cx in range(-7,8):
                for cy in range(-7,8):
                    for cz in range(-7,8):
                        v3 = calc_v3(bx,by,bz,cx,cy,cz)
                        if v3 != V[2]: continue
                        abv = calc_v2(ax,ay,az,bx,by,bz)
                        cav = calc_v2(ax,ay,az,cx,cy,cz)
                        bcv = calc_v2(cx,cy,cz,bx,by,bz)
                        v2 = abv + cav + bcv - 3*v3
                        if v2 != V[1]: continue
                        v1 = 7**3*3 - 2*v2 - 3*v3
                        if v1 != V[0]: continue
                        print("Yes")
                        print(ax,ay,az,bx,by,bz,cx,cy,cz)
                        exit()

print("No")

ABC343 D - Diversity of Scores

atcoder.jp

問題

  • N人の選手がコンテストに参加するよ。みんな最初は0点だよ
  • 今から$i$秒後に、選手$A_i$が、$B_i$点増加するよ
  • $i+0.5$秒後に、選手たちの得点は何種類?

成約

  • $1 \leq N,T \leq 2 \times 10^{5}$
  • $1 \leq B_i \leq 10^{9}$

思考

  • 大人しくシミュレーションしていくけど、毎秒全員の点数を確認するのは間に合わないので…
  • それぞれの選手の「今何点?」と、「◯点の選手は今何人?」を持って更新していく

コード

N,T = map(int,input().split())

score_L = [0]*N
score_d = defaultdict(int)
score_d[0] = N

for _ in range(T):
    A,B = map(int,input().split())
    A -= 1

    score_d[score_L[A]] -= 1
    if score_d[score_L[A]] == 0:
        score_d.pop(score_L[A])

    score_L[A] += B
    score_d[score_L[A]] += 1

ABC343 C - 343

atcoder.jp

問題

  • 正整数Nが与えられるよ
  • 正整数以下の回文立方数のうち、最大値を教えてね

成約

  • $1 \leq N \leq 2 \times 10^{18}$

思考

  • N以下の回文ではない立方数を考えてみる
    • $10^{6}^{3} = 10^{18}$なので、$10^{6}$まで、順に3乗の値を見ていけば良さそう

コード

N = int(input())

ans = 1
tmp = 1

while tmp**3 <= N:
    if str(tmp**3) == str(tmp**3)[::-1]:
        ans = tmp**3
    tmp += 1

print(ans)

ABC342 E - Last Train

atcoder.jp

問題

  • N個の駅があるよ!
  • 電車の情報がM個与えられるよ!
    • 駅Aから駅Bまで、cの時間がかかるよ!
    • l,l+d,l+2d,...,l+(k-1)dの時刻に駅Aから列車が発車するよ!
  • 以下の一覧を求めてね!
    • 駅1から駅Nに到着できる最終時刻
    • 駅2から駅Nに到着できる最終時刻
    • 駅3から駅Nに到着できる最終時刻…
    • 駅N-1から駅Nに到着できる最終時刻

成約

  • $2 \leq N \leq 2 \times 10^{5}$
  • $1 \leq M \leq 2 \times 10^{5}$

思考

  • 駅がN個、線路がM本…それぞれの線路の長さ(c)が、あるので、ダイクストラを疑う
  • 辺がM本なら、簡単にダイクストラで…地点Nからの最短距離が求められるよね
    • 今回は最終時刻がほしいので、プラスマイナス気をつけなきゃね
  • 問題は、辺の上限がとても多いので…$10^{14}$本とか貼るのは流石にえげつない…
    • M本の路線それぞれに応じて、乗るべき最終電車が一本決まるからこれをどうにか見つけたいね!
    • rangeにbisectが使える!すごい!
      • $10^{9}$の配列を作らなくても、等差数列の二分探索ができる!すごい!
    • 計算一発系でもいけそうだけど、上手く纏めるの難しい…

コード

from bisect import bisect_right
from heapq import heappush, heappop

N,M = map(int,input().split())
edge_L = [[] for _ in range(N)]
for _ in range(M):
    l,d,k,c,A,B = map(int,input().split())
    A-=1
    B-=1
    edge_L[B].append((range(l,l+k*d,d),c,A)) # rangeオブジェクトで辺の情報を取得

time_limit = [-float('inf')]*N
time_limit[-1] = float('inf')

hq = []
hq.append((-float('inf'),N-1))

while hq:
    time,now_node = heappop(hq)
    time = -time

    if time_limit[now_node] > time:continue

    for r,c,next_node in edge_L[now_node]:
        idx = bisect_right(r,time-c)
        if idx == 0:continue

        next_time = r[idx-1]

        if time_limit[next_node] >= next_time:continue
        time_limit[next_node] = next_time
        heappush(hq,(-time_limit[next_node],next_node))

for time in time_limit[:-1]:
    if time == -float('inf'):
        print("Unreachable")
    else:
        print(time)