Atcoder Beginner Contest #011
ABC過去問解きその4。D問題で多少手こずったがなんとか自力で解答できた。数学得意な人のD問題の解答が理解できなくてつらい。問題はこちら。
A: 来月は何月?
月が与えられるので、翌月の月を答える問題。12月の次は1月なのに注意。
print int(raw_input())%12+1
B: 名前の確認
アルファベット文字列が与えられるので、最初の文字を大文字、それ以外を小文字にして出力する問題。pythonには title() メソッドがあり、与えられた文字列の最初の文字を大文字、それ以外を小文字にしてくれる。
print raw_input().title()
C: 123引き算
ある正の整数 N が与えられる。1回の操作で1か2か3を引いていき、100回以内の操作で0にしたい。しかし3つのNG数があり、操作の途中これら数字になってしまったら失敗とみなす。それでは与えられた数字を無事0にすることができるかどうかを答える問題。
実際に与えられた数字を引いていけばいい。操作数を抑えたいので、3で引ける時は3で、だめなら2で、それもだめなら1で引いていく。途中引くことができなかったり、100回以内の操作で0にできなかったら0にすることができない場合となる。
N = int(raw_input()) NG = sorted([int(raw_input()) for _ in range(3)]) for roop in range(100): if N in NG: print "NO" break if N-3 >= 0 and N-3 not in NG: N -= 3 elif N-2 >= 0 and N-2 not in NG: N -= 2 elif N-1 >= 0 and N-1 not in NG: N -= 1 else: print "NO" break if N == 0: print "YES" break else: print "NO"
D: 大ジャンプ
あなたははじめ (0,0) にいるが N 回のジャンプで (X,Y) に移動したい。ただし、ジャンプを一回行うとつぎの4つの移動のどれか1つがランダムで選ばれる。
- X 軸に平行に +D だけ移動する。
- X 軸に平行に −D だけ移動する。
- Y 軸に平行に +D だけ移動する。
- Y 軸に平行に −D だけ移動する。
それでは N 回のジャンプ後にあなたが (0,0) から (X,Y) に移動できている確率はいくらか、という問題。 十字路が張り巡らされた街で、ある場所から目的の場所への行き方は何通りありますか?という問題の拡張版のようなもの。
自分のやり方は次のような感じ。それぞれの軸の+とーのジャンプ数を探索し、ジャンプ数の合計が N に合うとき、 ansにそれらの並び替えの組み合わせ数を足しあわせていく。最後に4Nで割って確率を求めるというもの。
このやり方はあまり賢いやり方ではないように思える。最後に4で割っていくとき、最初ansは超長大整数の場合があり、そのまま4.0で割ったり1.0を掛けたりしてfloatに直そうとすると "long int too large to convert to float" というOverflowエラーになってしまう。そこで求められる精度である10^-9を実現できる10桁程度まで整数による割り算を行い、そのあと実数に変換して割り算を継続している。はじめてこういうエラーが出たので戸惑ったが、テストケースの名称が条件そのままだったのでデバッグが楽に出来た。ありがたい。
fact = {i:0 for i in range(1001)}
# 階乗を返す。一度計算した値は保存しておく。
def f(n):
res,nn = 1,n
while n > 0:
if fact[n] > 0:
res *= fact[n]
return res
res *= n
n -= 1
fact[nn] = res
return res
N,D = map(int,raw_input().split())
X,Y = map(int,raw_input().split())
ans = 0
for px in xrange(N+1):
if px*D-X < 0 or (px*D-X)%D != 0: continue
dx = (px*D-X)/D
for py in xrange(N-px-dx+1):
if py*D-Y < 0 or (py*D-Y)%D != 0: continue
dy = (py*D-Y)/D
if px+dx+py+dy == N:
# 矢印の並び替えを思い描いてもらえばわかりやすいと思います
ans += f(N)/f(px)/f(dx)/f(py)/f(dy)
for i in range(N):
if len(str(ans)) > 14: ans /= 4
else: ans /= 4.0
print "%.15f"%ans