ABC001 解説
-
Upload
atcoder-inc -
Category
Technology
-
view
5.159 -
download
2
description
Transcript of ABC001 解説
AtCoder Beginner Contest 001解説
AtCoder 株式会社 代表取締役高橋 直大
コンテストデータ• こちらより入出力のダウンロードが可能
です– http://www.chokudai.info/atcoder/ABC001.rar– 個人サーバーですので、不安定な可能性があ
ります。
A 問題概要• 整数が 2 つ与えられます。引き算した結果
を求めなさい。– 整数の値は、 0 以上 2000 以下
A 問題 解説• まず、 2 つの整数を、標準入力から読み取
る– C 言語なら scanf, C++ なら cin など– 解らない場合は、 practice から各言語の例が
参照できます。– http://practice.contest.atcoder.jp/tasks/practice_1
• 読み取った2つの式を引き算• 出てきた値を出力する– こちらもわからない場合は practice から確認
B 問題概要• 距離を表す整数が与えられる• これを、 VV という単位に変換する– これは、距離によって場合分けで決定される
B 問題 解説• 整数を読み込んで、場合分け– 0.1km 未満なら~– 5km 未満なら~• 解らない場合は if ~ else 節について調べよう!
• 全て m 単位に揃えてあげると簡単
C 問題 問題概要• 風程・風向の角度が与えられる• これを、風力、風向 (16 方位 ) に変換しな
さい
C 問題 解説• やることは、 B 問題と全く同じ!– 風程も風向も、場合分けして変換してあげる
だけ!• でも、 if 文を大量に書くような実装をして
はいけません!– 通るけれども、面倒だし、バグも出やすい
C 問題 風向きの処理• 16 方位の間隔は全て一定– 全部の if 文を書かずに、繰り返しで処理できる!
• 全ての間隔は 22.5 度間隔なので、 22.5 度ずつ増やして判定する
– もっと簡単に、数式で一発で表すことも可能• ((Dis * 10 + 1125) / 2250) % 16 などの処理で、 0 ~ 15 の
数字に変換できる• N,NNE などの方向を表す文字列は、配列とし
て書いておく– 問題文からコピーして抽出しても良い
C 問題 風速の処理• 風程を 60 で割ると、風速になる– この割り算の処理が凄く危険!!
• 例えば、風程 201m だと風速 3.35m/s だが、3.35 は風力の境界線上– 誤差で少しでもずれると、間違った判定をし
てしまう。• 3.3499999999999…. だと、風力 2• 3.3500000000000…. だと、風力 3
C 問題 小数の対策方法• 基準となる風力を、逆に風程に変換する– 風速 3.35m/s 以下 → 風程 201m 以下
• 少しだけ小さい値を足してあげる– 3.499999.. + 0.00001– 3.500000.. + 0.00001– どちらも風力 3 となる• 入力が整数のみだから使える方法なので注意!• 入力間隔が細かいときなどは使えない場合があり
ます
C 問題 風速の処理• 入力が面倒!– とりあえずコピペして、数字だけ抽出するよ
うなプログラムをさくっと書こう!• それが面倒な人は、手入力や1つずつコピペが早
いと思います。• 英語しか読み込めないテキストエディタで開い
て、 ? を消去、なんて手もあります– 必要な数字を配列に入れてしまえば、繰り返
し判定するだけ!
D 問題 問題概要• 雨が降った期間が複数与えられる• マージしなさい
D 問題 前処理• データを丸める– 1357-1457 → 1355-1500
• やり方– まず時間と分を、分だけの単位に変換する• 1時間を 60 分として、 0 時 0 分から何分経ったか、
に変換する– 5 で割った余りに対して、足したり引いたり
を行う
D 問題 解説• それぞれの間隔において、配列を用意して
あげる
0:00 1:00
D 問題 解説• それぞれの間隔において、配列を用意して
あげる初期値は全て 0• 入力に対して、その範囲を 1 で塗りつぶす– 例: 0:20 – 0:45
0:00 1:00
D 問題 解説• それぞれの間隔において、配列を用意して
あげる初期値は全て 0• 入力に対して、その範囲を 1 で塗りつぶす– 例: 0:20 – 0:45 の後追加で、 0:10 – 0:40
0:00 1:00
D 問題 解説• それぞれの間隔において、配列を用意して
あげる 初期値は全て 0• 入力に対して、その範囲を 1 で塗りつぶす– 例: 0:20 – 0:45 の後追加で、 0:10 – 0:40
• 左から順番に、連続した範囲を調べる0:00 1:0
0
D 問題 高速な解法 1
• 入力をソートしよう!
D 問題 高速な解法 1
• 開始時間が早い順にソートする
D 問題 高速な解法 1
• ソートしてしまえば、順番に処理してあげれば、範囲を更新出来る。– 例えば、 10:00 – 11:30 の後に、 10:30-12:30 が
来た場合• 10:00-12:30 に更新する
– その後 13:30-14:00 が来た場合• 10:00-12:30 を出力し、 13:30-14:00 をメモリに入れ
る– その後 13:40-13:50 が来た場合• 更新する部分がないので何もしない
D 問題 高速な解法 2
• 座標を圧縮しよう–事前に境界線を調べておいて、その範囲しか
調べない!
0:00 1:00
0:00 1:00
D 問題 高速な解法 3
• 通称「いもす法」を使おう!– いままでのやり方
– いもす法(始点に1、終点の 1 個先に -1 を入れる)
0:00 1:00
0:00 1:00
1 -1
D 問題 高速な解法 3
• 色んな範囲に対して、始点に 1 を足して、終点に -1 を足す、を繰り返す
0 1 1 1 0 1 -1
1:00
-1 0 0 -1 -1
D 問題 高速な解法 3
• 作った配列に対して、そこまでの足した値を計算してあげる–元の配列
– 足した配列
0 1 1 1 0 1 -1
1:00
-1 0 0 -1 -1
0 1 2 3 0 1 02 2 2 1 0
D 問題 高速な解法 3
• この配列の、数字が 1 以上になっている範囲が、求める範囲– 入力範囲が増えても、始点と終点だけを入れ
れば良いので、配列すべてをなぞるのは1回だけで良い!
0 1 2 3 0 1 02 2 2 1 0