Xenous の精進記録

AtCoder関連他、学習したことの記録です。

バーチャル参加 ABC001

  • 4完2ペナ 81分でした
  • アルゴリズムというよりゴリゴリの実装問題ですね。意外と実案件ではこのようなデータの整形に出くわす場面が多く、なんだかんだこういう問題も役に立つと思います。

A - 積雪深差

入力を受け取って引き算して返します。

B - 視程の通報

与えられるテストケースの制約の記載があります。ルールにしたがって計算したときに整数にならないことはないので、切り捨ての割り算で整数型のまま計算できそうです。

あとは書かれた条件を ifelifelse を使って記述します。

C - 風力観測

結構面倒な問題です。B問題と同じく if else をたくさん書けば実装はできます。 無駄なく書こうとするとちょっと考えてしまいますね。私が思いついたのは次の二つです。

  • for 文で回せるところは回す
  • エディタの複数選択を使う

これらで時短しつつ、条件をコードに落とします。 誤差については、float で扱わず、Decimal で計算してしまえば問題なさそうです。四捨五入や切り捨てなども Decimal を使います。

  • 小数点の四捨五入(風速の計算で使用)
from decimal import Decimal, ROUND_HALF_UP

# 風向、風程
Dig, Dis = map(str, input().split())

# 条件に合わせるための処理
DDig = Decimal(Dig)/10
DDis = Decimal(Decimal(Dis)/60).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP)  # 秒速にして小数第二位で四捨五入

float 型で小数点どうしの引き算や割り算を行うと誤差が生じます。多少の計算であれば問題ないのですが、大きな数をかけたり複数の処理を噛ませると誤差が大きくなり結果間違えることは往々にしてあるので、気をつけましょう(自戒)。

17.2 - 20.8
# -3.6000000000000014

D - 感雨時刻の整理

これも結構面倒です。入力された時刻を条件通りに丸めることと、結合することの2種類の操作を行います。

条件通りに丸める方法は、次のようにすることでできます。

  • 降り始めの時刻は、5で割ったあまりを引く
  • 降り止んだ時刻は、5で割ったあまりを5から引いた値を足す。ただし5で割ったあまりが0なら何もしない。
    さらに、100で割ったあまりに対して、それが 「0 でない」かつ 「さらに 60 で割ったあまりが 0」なら40を足す。

もっとスマートにやれそうですが、ひとまずこんな感じでできます。

# '-' で分割した値を格納
fr, to = input().split('-')
# 丸める
fr -= fr%5
to += (5 - to%5) * (to%5 != 0)
# 繰り上げ処理
to += 40 * ((to%100)%60 == 0 and (to%100 != 0))

次に時間の結合を行います。 まず降り始めた時間でソートしておきます。そうすると、降り止んだ時間が、次の降り始めた時間より遅いのであれば、結合することができます。 そうでない時は結合せず別物として扱います。

最後に0埋めをしつつ形式に合わせて表示すれば回答できます。

まとめると、以下のように実装できます。

# 入力
N = int(input())
l = []
for _ in range(N):
    fr, to = input().split('-')
    fr = int(fr); to = int(to)
    fr -= fr%5; to += (5 - to%5) * (to%5 != 0)
    # 繰り上げ処理
    to += 40 * ((to%100)%60 == 0 and (to%100 != 0))
    l.append((fr, to))

# 降り始めの時刻でソート
l.sort(key=lambda x: x[0])

ans = []
bf_fr, bf_to = l[0]
for i in range(N-1):
    af_fr, af_to = l[i+1]

    # 降り止んだ時刻の後に降り始めた時刻が来ている場合は別物扱いする
    if bf_to < af_fr:
        ans.append((bf_fr, bf_to))
        bf_fr, bf_to = af_fr, af_to
    # 降り止んだ時刻の前に降り始めた時刻が来ている場合はまとめる
    else:
        bf_to = max(bf_to, af_to)

# 最後の分を追加する
ans.append((bf_fr, bf_to))

# zfill で先頭を 0 埋めしてから表示する。
for fr, to in ans:
    fr = str(fr).zfill(4)
    to = str(to).zfill(4)
    res = fr + '-' + to
    print(res)

意外と時間がかかってしまいました。昔と今だと問題のテイストも結構違いましたね。