気まぐれブログ(日記・技術記事・研究のことなど)

気まぐれに更新します.温かい目で見ていただければ...

ABC156 D問「Bouquet」

問題リンク

atcoder.jp

問題文

f:id:tomonori4565:20200223163827p:plain

回答プログラム

import math
n, a, b = map(int, input().split(" "))
mod_num = 10**9 + 7

# n, aは正整数(n >= a), pは素数
def comb_mod(n, a, p):
  X = 1
  for num in range(n, n-a, -1):
    X *= num
    X %= p
  Y = math.factorial(a) % p
  return (X * (pow(Y, p-2, p))) % p

print((pow(2, n, mod_num) - (comb_mod(n, a, mod_num) + comb_mod(n, b, mod_num) + 1)) % mod_num)

解説

冪剰余計算と組合せ剰余計算が必要となる問題. どちらも高速化できる手法があるので説明する.

まず冪剰余計算については,pythonの既存関数powを利用することで高速に求められる.

Example:

>>> pow(10, 3, 7)
6
>>> pow(10**9, 4000, 123456)
9088

一方,組合せ剰余計算については,少し工夫しないといけない. 以下の式変形を見てみよう.

f:id:tomonori4565:20200223164615j:plain

組合せ「剰余」計算においては,上記の式変形を利用して高速計算できる(ただしpは素数).理由としては,Yp-2pow関数を利用することで高速に計算できるためである.

この手の問題が出たら,いちいちアルゴリズムを考えるのは手間なので,すぐ利用できる形でドキュメントに残しておくと良いかもしれない.