ABC267の振り返り(A, B, C, D)
振り返りです。
A - Saturday
やってみよう!
A
関数を完成させて「Run」ボタンをクリックしよう!(テストデータ省略)
自由欄
try
def A(S): return 5 - [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", ].index(S) print(A("Wednesday")) # 3 print(A("Monday")) # 5結果:提出 #34535168
自由欄
B - Split?
やってみよう!
B
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
try
以下がコンテス中にACした回答。
色々とかっこ悪いです。
結果:提出 #34546981
解説を見る
こちらの解説で紹介されているのが、ピンの立っている列の集合を使ってスプリットを判定するというもの。
なるほどなぁ。
結果:提出 #34797483
自由欄
try2: n本のピンに対応
本筋からは逸れますが、ピンの立っている列をハードコーディングするのが気になります。
という訳でピンの本数から列番号を生成する関数を作ってみました。
が、やっぱりかっこ悪い…
①素朴な実装
def to_column(size, first_pin_col=0): if size < 1: return [] ret = [first_pin_col] i = 1 # 2行目のピンから見ていく cnt = 1 while True: edge = ret[0] - i for j in range(i + 1): if cnt == size: break ret.append(edge + 2 * j) cnt += 1 else: i += 1 continue break return ret②短くしてみた
from math import ceil from itertools import chain def to_column(size, first_pin_col=0): rows = ceil((2 * size + 0.25)**(1/2) - 0.5) return list(chain.from_iterable( [[first_pin_col - r + c for c in range(0, (r+1)*2, 2)] for r in range(rows)] ))[:size]戯れに描画関数も作ってみました。
描画関数定義:print_pins
以下のように使用できます。
pins, = test_dataB[0]["in"] print_pins(pins, to_column(len(pins)))10本以上でもOK
import random n = 55 pins = random.choices(["0", "1"], k=n) print_pins(pins, to_column(n))行が全部埋まらなくてもOK
import random n = 100 pins = random.choices(["0", "1"], k=n) print_pins(pins, to_column(n))上の回答をto_column
関数に置き換え
結果:提出 #34801018
自由欄
C - Index × A(Continuous ver.)
C - Index × A(Continuous ver.)
やってみよう!
C
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
try1
時間内にACならず。
まず素朴に実装したのがこちら。
結果:TLE x 22
提出 #34555434 - NECプログラミングコンテスト2022 (AtCoder Beginner Contest 267)
自由欄
try2
なにかしら前処理が必要だと考え頭を捻ったものの$O(NM)$から逃れられず…
ダメ元でnumpy
使ってみたけどやっぱりダメでした
結果:TLE x 22, MLE x 1
初めてMLE(メモリ制限超過)
が出た😂
提出 #34565855 - NECプログラミングコンテスト2022 (AtCoder Beginner Contest 267)
自由欄
解説
という訳で解説を見ます。
pythonで書き換えるとこんな感じ。
結果:AC
提出 #34600152 - NECプログラミングコンテスト2022 (AtCoder Beginner Contest 267)
解説を理解する
サンプルデータの2つ目を例に考えます。
N, M, A = test_dataC[1]["in"] A = np.array(A) N, M, A # 縮小表示 import pandas as pd import jinja2 df = pd.DataFrame( np.stack( [np.concatenate([[0]*i, A[i:i+N-M+1]*(i+1), [0]*(M-1-i)]) for i in range(M)], ), columns=range(1, 11), dtype=int ) df.index = [ "x1", "x2", "x3", "x4", ]まずは4行目で、$A_1$から選んだ$\sum^{M}_{i=1}i \times B_i$を計算します。
# 縮小表示 style_str = lambda _: "background: lightgreen; font-weight: bold" sty = df.style for i, label in enumerate(df.index, 1): sty = sty.applymap(style_str, subset=(f"{label}", i)) sty sum(A[i] * (i + 1) for i in range(M))次に$A_2$から選んだ場合の値を計算したいのですが…
# 縮小表示 style_str = lambda _: "background: aqua; font-weight: bold" sty = df.style for i, label in enumerate(df.index, 2): sty = sty.applymap(style_str, subset=(f"{label}", i)) sty以下の式のように、すでに計算した値から該当範囲の累積和を引いて最終項を加えることで算出できます。
$$ \begin{matrix} & 1 \times A_1 & + & 2 \times A_2 & + & 3 \times A_3 & + & 4 \times A_4 & &\\ -) & A_1 & + & A_2 & + & A_3 & + & A_4 & - & 4 \times A_5 \\\hline & & & 1 \times A_2 & + & 2 \times A_3 & + & 3 \times A_4 & + & 4 \times A_5 \\ \end{matrix} $$
という処理を行っているのが5,6行目ということですね。
はぇ~、すっごい
D - Index × A(Not Continuous ver.)
D - Index × A(Not Continuous ver.)
やってみよう!
D
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
try
コンテスト中、C問題に行き詰まってD問題を解こうと試みましたが、DP使うんだろうことは想像できても「選ぶ場合と選ばない場合をどうすりゃええや…」となってお手上げでした。
以下は解説参照。いざ正答を見るとこれしかないって感じです。
max
で大きい方を採るのね、はいはい。ちくしょー!😭
結果:提出 #34601411 - NECプログラミングコンテスト2022 (AtCoder Beginner Contest 267)
解説でなぜ-1000000000000000000ll
を初期値としてるのか最初分からなかったのですが、$A_i$が全て$-2 \times 10^5$で$M = N = 2000$だった場合、最大値は$-40002000000000$になります。
比較する初期値としてはそれよりも小さくなければならない、ということで上のコードでは-10**14
としました。
自由欄