久しぶりにAtCoderに参加しました。D問題の公式解説が動的計画法を使っていて難しかったので、自分なりの解法をメモしておきたいと思います。用いるのは高校で習う数学Aの知識です。まずは問題文のおさらいです。
問題文:整数 が与えられます。 すべての項が 以上の整数で、その総和が であるような数列がいくつあるか求めてください。ただし、答えは非常に大きくなる可能性があるので、 で割った余りを出力してください。
制約 :1 ≤ S ≤ 2000, 入力はすべて整数
例として、 S = 11 のときを考えてみましょう。まず数列の最大の項数を考えます。すべての項が3以上という条件から11 ÷ 3 = 3 ・・・ 2 で最大の項数は3であることがわかります。それでは項数が3のとき、S = 11となる数列はいくつ存在するでしょうか。ここでは、玉と箱を用いて考えます。今回はS = 11かつ項数3なので玉を11個、箱を3つ用意しました。箱の中に入っている玉の数が数列の各項に対応します。まず箱には少なくとも3つの玉が入っている必要があるので、あらかじめ3つずつ玉を入れておきます。すると、残った2つの玉を3つの箱に振り分ける方法は何通りあるか、という問題に帰着します。たとえば前2つの箱に1個ずつ入れると、これは数列{4, 4, 3}に対応しています。数列{4, 4, 3}は確かにS = 11かつ項数3の数列ですね。
- 入力Sに対して最大の箱の数を求める。
- 最大の箱の数をXとする。箱の数が1からXのときそれぞれに対して以下の計算を行う。
・あらかじめ箱に入れておく玉を入力Sからひく。
・残りの玉の箱への入れ方が何通りあるか求める。 - 箱の数が1のときからXのときまでの残りの玉の箱への入れ方を合計する。答えを で割る。
from math import factorial S = int(input()) ans = 0 for i in range(S // 3): box = i + 1 # 箱の数 ball = S - 3 * box # あらかじめ箱に3こずつ入れたあとの残りの玉の数 # 箱への入れ方が何通りあるか計算。 # 仕切りの数は box - 1 であることに注意 ans_ = factorial(ball + box - 1) // (factorial(ball) * factorial(box - 1)) ans += ans_ print(ans % (10 ** 9 + 7))
久しぶりのAtCoder、とても楽しかったです。次も頑張りたいなと思います。
0 件のコメント:
コメントを投稿