C問題をACできなかった因縁の回。
というわけで振り返りです。
AtCoder Beginner Contest 259 - AtCoder
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
def test_all(f):
for i, data in enumerate(eval(f"test_data{f.__name__[0]}")):
exp = data["out"]
ans = f(*data["in"])
result = "AC" if exp == ans else "WA"
print(f"{i+1} {result}: expected: {exp}, output: {ans}")
A - Growth Record
A - Growth Record
やってみよう!
A
関数を完成させて「Run」ボタンをクリックしよう!
test_dataA = [
{"in": [38, 20, 17, 168, 3], "out": 168},
{"in": [1, 0, 1, 3, 2], "out": 1},
{"in": [100, 10, 100, 180, 1], "out": 90},
]
def A(N, M, X, T, D):
pass
test_all(A)
自由欄
try
こんな感じ
def A(N, M, X, T, D):
return T - D * (X - M) if M < X else T
test_all(A)
結果:提出 #34108134
自由欄
def A(N, M, X, T, D):
return ([T]*(N-X)+[T-D*i for i in range(X+1)])[::-1][M]
test_all(A)
結果:
B - Counterclockwise Rotation
B - Counterclockwise Rotation
やってみよう!
B
関数を完成させて「Run」ボタンをクリックしよう!
test_dataB = [
{
"in":[2, 2, 180],
"out": [-2, -2]
},{
"in":[5, 0, 120],
"out": [-2.49999999999999911182, 4.33012701892219364908]
},{
"in":[0, 0, 11],
"out": [0.00000000000000000000, 0.00000000000000000000]
},{
"in":[15, 5, 360],
"out": [15.00000000000000177636, 4.99999999999999555911]
},{
"in":[-505, 191, 278],
"out": [118.85878514480690171240, 526.66743699786547949770]
},
]
import numpy as np
def test_B(f):
for data in test_dataB:
i, o = data.values()
ans = f(*i)
if ans is None: return
if np.allclose(ans, o, rtol=1e-6, atol=0) or np.allclose(ans, o, rtol=0, atol=1e-6):
print("AC: ", end="")
else:
print("WA: ", end="")
print(f"expected: {o}, output: {ans}")
def B(*n):
pass
test_B(B)
自由欄
try
コンテスト中の提出はひどいものだったので、改めてこんな感じ。
回転行列を作ってnumpyで行列とベクトルの積を計算してます。
実際これぐらいの計算であればnumpyも不要ですが。
import numpy as np
def B(a, b, d):
s = np.sin(np.deg2rad(d))
c = np.cos(np.deg2rad(d))
return np.matmul([[c, -s], [s, c]], [a, b])
test_B(B)
結果:提出 #34126212
回転行列の復習
個人的な理解なので、検索したらもっと分かりやすい説明があると思います。
点$(a, b)$の原点との距離を$r$、x軸からの角度を$\phi$とします。ここで、$
\begin{pmatrix}
a \\
b
\end{pmatrix} = \begin{pmatrix}
r \cos\phi \\
r \sin\phi
\end{pmatrix}
$ です。
原点を中心に$\theta$だけ回転させた点$(a', b')$は以下のようになります。
$$
\begin{aligned}
& \begin{pmatrix}
a' \\
b'
\end{pmatrix} && \\
= \:&\: \begin{pmatrix} % 極座標から直交座標
r\cos\big(\phi+\theta\big) \\
r\sin\big(\phi+\theta\big)
\end{pmatrix} && 極座標系から直交座標系に変換\\
= \:&\: \begin{pmatrix} % 加法定理
r\big(\cos\phi\cos\theta - \sin\phi\sin\theta\big) \\
r\big(\sin\phi\cos\theta + \cos\phi\sin\theta\big)
\end{pmatrix} && 加法定理\\
= \:&\: \begin{pmatrix}
a\cos\theta - b\sin\theta \\
b\cos\theta + a\sin\theta
\end{pmatrix} && \\
= \:&\: \begin{pmatrix}
\cos\theta & -\sin\theta \\
\cos\theta & \sin\theta
\end{pmatrix} \begin{pmatrix}
a \\
b
\end{pmatrix} &&
\end{aligned}
$$
自由欄
C - XX to XXX
C - XX to XXX
やってみよう!
C
関数を完成させて「Run」ボタンをクリックしよう!
test_dataC = [
{
"in":['abbaac', 'abbbbaaac'],
"out": "Yes"
},{
"in":['xyzz', 'xyyzz'],
"out": "No"
},
]
def C(S, T):
pass
test_all(C)
自由欄
try
コンテスト中にACできなかったが、その後当日中にACしてたらしい。(記憶がない)
その時の提出を見てもあまり読む気にならないようなコーディングなので改めてやってみたのが以下。
だいたい解説と同じような実装になりました。
def enc(s):
ret = [["", 0]]
for c in s:
if c == ret[-1][0]: ret[-1][1] += 1
else: ret.append([c, 1])
return ret
def C(S, T):
s = enc(S)
t = enc(T)
if len(s) != len(t): return "No"
for c1, c2 in zip(s, t):
# 文字が違う
if c1[0] != c2[0]: return "No"
# 同じ文字、同じ数
if c1[1] == c2[1]: continue
# Sの文字数が多ければNG
if c1[1] > c2[1]: return "No"
# Tの文字数が多いけどSの文字数が2未満だと操作できないのでNG
if c1[1] < 2: return "No"
return "Yes"
test_all(C)
結果:提出 #34153172
場当たり的にロジックを組んでたらバグる、そしてちゃんとしたロジックを組むために最適なデータ構造を選ばなければならない、という教訓の1問です。
自由欄
D - Circumferences
D - Circumferences
やってみよう!
D
関数を完成させて「Run」ボタンをクリックしよう!
test_dataD = [
{
"in": [4, [0, -2], [3, 3], [[0, 0, 2], [2, 0, 2], [2, 3, 1], [-3, 3, 3]]],
"out": "Yes"
},{
"in": [3, [0, 1], [0, 3], [[0, 0, 1], [0, 0, 2], [0, 0, 3]]],
"out": "No"
},
]
def D(N, s, t, circles):
pass
test_all(D)
自由欄
try
せっかくなのでコンテスト中は見ることもなかったD問題もやってみます。
なんだか小難しそうですが、全ての円の中心と点s, tを頂点とするグラフを作りながら全探索すればよいのでは?
というわけで以下。
from collections import deque
def D(N, s, t, circles):
def check(a, b):
d2 = (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2
return d2 <= (a[2] + b[2]) ** 2 and d2 >= (a[2] - b[2]) ** 2
circles = [s + [0]] + circles + [t + [0]]
q = deque([0])
remined = set(range(1, N+2))
while len(q):
now = q.popleft()
for c in list(remined):
if check(circles[now], circles[c]):
if c == N + 1: return "Yes"
q.append(c)
remined.remove(c)
return "No"
test_all(D)
結果:提出 #34189988
自力ACできた!解説の考え方とも大差なさそうです。
自由欄
まとめ
1ヶ月ちょっとの間でも自分の成長を感じる今日このごろ。
「振り返ってできる」から「本番でできる」まで成長せねば!
自由欄