Official

C - Duodecim Ferra Editorial by QCFium


分割場所を全探索すると \(\Theta(L^{12})\) の計算量がかかって実行時間制限超過となります。もう少し工夫した方法を考えましょう。
まず、分割後の各棒の長さが全て正整数になるためには、西から整数長さの場所以外を切ってはいけません。逆に西から整数長さの場所から異なる \(11\) 個の位置で切れば分割後の各棒の長さは全て正整数になります。
つまり、切る位置の候補が \(L - 1\) 個あり、そこから異なる \(11\) を選ぶ (\(11\) 個の順番は区別しない) 場合の数を求めればよいです。
これは \(_{L - 1}C_{11} = \frac{(L - 1)(L - 2)(L - 3) \dots (L - 11)}{11!}\) に等しいです。
注意しなければいけないのは、この分数自体の値は \(2^{63}\) 未満ですが、分子は \(64\) bit 整数型に収まらないことがあるという点です。オーバーフローを回避する方法はいくつかあります。

  • パスカルの三角形を用いた計算を行う
    パスカルの三角形の上から \(i\) 段目(0-indexed)の左から \(j\) 番目(0-indexed)には \(_iC_j\) が書かれます。
    一方で、パスカルの三角形を定義通り計算すると、\(_iC_j\) の計算過程に \(_iC_j\) より大きい値が出てこないので、オーバーフローせず正しく計算できます。
    ただし\(_iC_j\) がオーバーフローしなかったとしても、\(_iC_j\) の計算には関係ない \(i\) 段目の他の場所などでオーバーフローが起こる可能性はあります。(例 : \(_{199}C_{11} < 2^{63}\) だが \(_{199}C_{100} > 2^{190}\))
    このとき C++ などの言語では、符号付き整数を使っていると、このオーバーフローした値が答えに関わらなくても直ちにプログラム全体の動作が保証されなくなるので注意してください。
  • 順次割りながら計算する
    \(\frac{(L - 1)}{1!}, \frac{(L - 1)(L - 2)}{2!}, \frac{(L - 1)(L - 2)(L - 3)}{3!}, \dots, \frac{(L - 1)(L - 2)(L - 3) \dots (L - 11)}{11!}\) の順に計算していきます。ここにある数はそれぞれ \(_{L - 1}C_1, _{L - 1}C_2, _{L - 1}C_3, \dots, _{L - 1}C_{11}\) なので全て整数です。また、\(_{L - 1}C_{(i + 1)} = \frac{_{L - 1}C_i \times (L - (i + 1))}{(i + 1)}\) のように順番に計算していくことができます。
    計算過程で出てくる最大の数は今回の制約下では \(_{199}C_{11} \times 11\) で、\(2^{63}\) 未満なのでオーバーフローしません。
  • \(128\) bit 整数型を使う
    一部の言語、環境には \(128\) bit の整数型があり、分母は \(128\) bit 整数型には収まるので、これを使うとオーバーフローしません。( 例 : AtCoder の C++ では __int128 型が使える )

posted:
last update: