ABC260の振り返り(A, B, C, D)
初めて緑パフォが出ました!
という訳で振り返りです。
A - A Unique Letter
やってみよう!
A
関数を完成させて「Run」ボタンをクリックしよう!
(テストケース省略)
自由欄
try
こんな感じ。for
文のelse
節はbreak
が呼ばれなかった場合のみ実行されます。
(参照:8. 複合文 (compound statement) — Python 3.10.4 ドキュメント)
結果:提出 #33294563 - AtCoder Beginner Contest 260
自由欄
B - Better Students Are Needed!
B - Better Students Are Needed\!
やってみよう!
B
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
try
設問に従って素直に実装するとこんな感じ。
特に難しいことはありません。が、結構時間掛かってしまった…
ポイントとしては使用する言語で以下の点を把握していることでしょうか。
key
を指定したソート- 安定ソート
参照:ソート HOW TO — Python 3.10.4 ドキュメント
from operator import itemgetter as ig def B(N, X, Y, Z, A, B): ans = [] (*data,) = zip(range(1, N + 1), A, B) # 数学 data.sort(key=ig(1), reverse=True) n, *_ = zip(*data) ans.extend(n[:X]) data = data[X:] # 英語 data.sort(key=ig(0)) data.sort(key=ig(2), reverse=True) n, *_ = zip(*data) ans.extend(n[:Y]) data = data[Y:] # 合計 data = [(n, a + b) for n, a, b in data] data.sort(key=ig(0)) data.sort(key=ig(1), reverse=True) n, *_ = zip(*data) ans.extend(n[:Z]) return "\n".join(map(str, sorted(ans))) test_all(B)結果:提出 #33305130 - AtCoder Beginner Contest 260
自由欄
pythonのソートについて補足
listのsort
メソッドやsorted
関数は、"リストのリスト"などで特にkey
を指定せずとも動作します。
では、リスト同士の比較はどのように判断するのかというと、ちゃんとドキュメントに記載されています。
なので、[[得点, 出席番号]]
のようなlistを「得点の昇順、同点の場合は出席番号の昇順」で並べ替えたいときは一発で実現できてしまいます。
他の人のコードを見てみる
実行時間もコード長も短い回答を適当にピックアップしました。
下記はeugaltさんの提出を参考。すごいスッキリしてます。
(-得点, 番号)
とすることで「得点の降順、同点の場合は番号の昇順」での並べ替えを実現しています。
結果:提出 #33339060 - AtCoder Beginner Contest 260
C - Changing Jewels
やってみよう!
C
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
try
これも設問通りに実装すればいいだけです。手順が少ない分B問題より簡単ですね。
def C(N, X, Y): r = [0] * 11 b = [0] * 11 r[N] = 1 while sum(r[2:]) > 0: for i in range(10, 1, -1): if r[i]: r[i - 1] += r[i] b[i] = r[i] * X r[i] = 0 for i in range(10, 1, -1): if b[i]: r[i - 1] += b[i] b[i - 1] += b[i] * Y b[i] = 0 return b[1] test_all(C)結果:提出 #33309558 - AtCoder Beginner Contest 260
try2
上がコンテスト中の提出なんですが、見返すと無駄にループ回してます…
ので以下推敲。
def C(N, X, Y): r = [0] * (N + 1) b = [0] * (N + 1) r[N] = 1 for i in range(N, 1, -1): r[i - 1] += r[i] b[i] += r[i] * X r[i - 1] += b[i] b[i - 1] += b[i] * Y return b[1] test_all(C)結果:提出 #33339952 - AtCoder Beginner Contest 260
ちゃんと設問を理解すればスッキリしたコードに落とし込める、という好例ですね。
「よく理解してないけどいつか答え出るやろ笑」みたいな手抜きコーディングはやめよう…
自由欄
D - Draw Your Cards
やってみよう!
D
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
try1
この問題も、アルゴリズムというより実装力が求められるかと思います。
以下のコードでWA, TLEとなりコンテスト終了となりました。
恥ずかしいので先に言っておくと、WAの原因は6~9行目のアホみたいな分岐です(後述)。
from bisect import bisect from operator import itemgetter as ig def D(N, K, P): if K == 1: return "\n".join(map(str, P)) if K == N and P == sorted(P): return "\n".join(str(N) * N) ans = [-1] * (N + 1) ba = [] for i, v in enumerate(P, start=1): idx = bisect(list(map(ig(0), ba)), v) if idx == len(ba): ba.append([v]) else: if len(ba[idx]) == K - 1: for c in ba[idx]: ans[c] = i ans[v] = i ba.remove(ba[idx]) else: ba[idx].insert(0, v) return "\n".join(map(str, ans[1:])) test_all(D)サンプルではpassするが…
結果:提出 #33315198 - AtCoder Beginner Contest 260
try2
WAはとりあえず置いておいて、TLEをなんとかしたいです。
と言っても短いコードで処理も単純なので、怪しいのは15行目の「場に出ているカードの山から一番上に重ねられた数を取り出す」処理でしょう。
map(ig(0), ba)
解説では連想配列(dict)でなんだかんだと言っていて、確かにC++だとスッキリしたコーディングになっていますが、pythonのdictにはC++のmove
のようなメソッドありません。
無理やりdictで実装しようも、削除・追加で順序が崩れて面倒くさそう… (参照)
ていうか解説のpythonの実装例、なんだこれ…
どうしたもんかと他の人の回答(例えば提出 #33328762)を見て目から鱗が落ちました。
場に出てるカードの情報と一番上のカードの情報、別々でいいやん!
という訳で実装したのが以下。(参照した提出とほとんど同じになった…)
from bisect import bisect from operator import itemgetter as ig def D(N, K, P): if K == 1: return "\n".join(map(str, P)) if K == N and P == sorted(P): return "\n".join(str(N) * N) ans = [-1] * (N + 1) ba = [] top = [] for i, v in enumerate(P, start=1): idx = bisect(top, v) if idx == len(ba): ba.append([v]) top.append(v) else: yama = ba[idx] yama.append(v) top[idx] = v if len(yama) == K: for c in yama: ans[c] = i ba.pop(idx) top.pop(idx) return "\n".join(map(str, ans[1:])) test_all(D)結果:提出 #33331799 - AtCoder Beginner Contest 260
try3
無事TLEが解消されたところでWAを修正します。
前述の通り6~9行目が原因なんですが、もう投げやり感が否めません😩
自力でTLEを解消できなかったので同じ結果とはいえ、C問題の手抜きコーディングに引き続いて「ちゃんとしようね」と諭したくなります。ちゃんとしようね。
一応言語化しておくと、8,9行目は不要です。6,7行目のKが1の場合は、[引いたカードの数]と[ターン数]の組をカードの数で並べ替えて出力する必要があります。
という訳で以下。
from bisect import bisect from operator import itemgetter as ig def D(N, K, P): if K == 1: ans, _ = zip(*sorted(zip(range(1, N + 1), P), key=ig(1))) return "\n".join(map(str, ans)) ans = [-1] * (N + 1) ba = [] top = [] for i, v in enumerate(P, start=1): idx = bisect(top, v) if idx == len(ba): ba.append([v]) top.append(v) else: yama = ba[idx] yama.append(v) top[idx] = v if len(yama) == K: for c in yama: ans[c] = i ba.pop(idx) top.pop(idx) return "\n".join(map(str, ans[1:])) test_all(D)結果:提出 #33332745 - AtCoder Beginner Contest 260
無事ACとなりました。
なお、if K==1
を丸々削除し、25~29行目のif文のインデントを一段上げても同様にACとなります。(むしろこっちのほうがスッキリする)
結果:提出 #33332482 - AtCoder Beginner Contest 260
まとめ
ちゃんとしよ。