ABC 400 B問題 Sum of Geometric Series

目次

AtCoder beginner contest 400 に参加して、A と B の問題を正解できました。しかし、見直してみると B 問題 Sum of Geometric Series を正解できたとはいえひどいコードだったので修正した。


問題

AtCoder beginner contest 400B 問題 Sum of Geometric Seriesは、基本的にただ足し算をするだけ。ただし合計が 10^9 を超えた場合には、文字列 inf を表示する。

ですので、することは次のように成ります。

  1. 指定された値までループを回して加算を繰り返す。
  2. 合計が 10^9 を超えたらループを抜けて inf を表示する。

コンテスト内で正解にはなったものの、改めて見直してみるとひどいコードなので、振り返りながら修正してみました。

解決方法

コンテスト内で作成したコードは次のもので、正解に成りました。

n, m = map(int, input().split())

total = 0
try:
    for i in range(m + 1):
        total += n ** i
        if total > 1_000_000_000:
            total = "inf"
except TypeError:
    total = "inf"

print(total)

最初書いたコードは、10^9 を超えると次のようなエラーになってしまいました。

 Traceback (most recent call last):
  File "/home/nosuzuki/reposit/at_coder/ABC_400/B.py", line 20, in <module>
    total += n ** i
TypeError: can only concatenate str (not "int") to str

急いでいたのでエラーメッセージをよく見ずにとりあえずの対応でエラーを捕まえて無理やり inf を表示させて正解にしています。

エラーの原因

落ち着いてエラーメッセージを読むと、can only concatenate str (not "int") to strと書かれており、文字列の結合に問題があることが分かります。

そうです。最大値を超えている時に代入した inf に数値を結合しようとしたエラーです。これは、最大値を超えた時にループから抜ける break を忘れたため、次のループを実行してしまったためです。

そこで、次のように修正すれば例外に頼らないコードに成ります。

n, m = map(int, input().split())

total = 0
for i in range(m + 1):
    total += n ** i
    if total > 1_000_000_000:
        total = "inf"
        break

print(total)

それでも、意図的で Python では許されているとは言っても、数値が入っていた変数 total に文字列を入れることは褒められません。そこで、これをなんとかしたいと思いました。

そのためには最大値を超えたことをループ外で検出する必要があります。そこで方法としては、次の 3 つが思いつきました。

  1. 最大値を超えた時に、特別な値を変数 total に設定する。
  2. 最大値を超えた事を表すフラグを導入する。
  3. 何らかの方法で、break したことを検出する。

1 の特別な値(マジックナンバー)を入れることは推奨されないし、2 の条件判断をするためだけに変数を導入するのもスマートではありません。ということで、ループが break したか知ることができるか検索したら、else が使えることが分かりました1

ループ内で break が起きなかった場合 には、else ブロックが実行されます。そこで最終的には、次のように修正できます。

n, m = map(int, input().split())

total = 0
for i in range(m + 1):
    total += n ** i
    if total > 1_000_000_000:
        print("inf")
        break
else:
    print(total)
  • 最大値を超えた場合には、inf を表示してループを break で抜けます。
  • 最大値に達しなかった場合には、else ブロクが実行されて合計値が表示されます。

参考サイト