AtCoder ABC 156
February 23, 2020
ABC156 の自分用メモ
A | B | C | D | E | F |
---|---|---|---|---|---|
o | o | o | x | x | x |
A, B, Cは問題なく解くことができたが、Dで引っかかった。
D問題
https://atcoder.jp/contests/abc156/tasks/abc156_d
aとbを考慮せずn種類の花から1本以上選んで花束を作る方法は
で求められる(あるいはn種類の花それぞれについて選ぶ選ばないを考えて、すべてを選ばない場合を引いて)。そこからとを引いた値が求める答えとなることはわかったが、 という条件を見て、とが制限時間以内に計算できないと判断してしまった。解いてる最中は累乗と階乗が頭でごっちゃになっていたり、累乗etcのアルゴリズムについての理解不足が原因。以下、累乗、累乗の逆元、二項係数それぞれについてまとめる。
累乗
について求めたいとする。愚直に求めると
のように となる。しかし、
と計算できることを考慮すると、
で求めることができ、この場合となる。求めたい累乗は必ずしも2のn乗とはならないから一般的にを求めるときに、この方法を応用できないかを考える。はで計算できることがわかっているので、nを2の累乗の和に分解できれば、
のように計算できる。累乗和への分解は、nを二進数にしたとき、i桁目が1かどうかを調べることでできる。これを踏まえると、以下のコードでがで計算できる。
も同様に求められる。今回のD問題のようにmodをとる必要がある問題も多いが、累乗は乗算しかおこなわないので、各計算ごとにmodをとればも計算できる。
累乗の逆元
modを取らない場合は、上の方法で累乗を求めて割ればいいだけなので、におけるの逆元を求める方法についてまとめる。以下pを法とする。求める方法は2つある。
- Fermatの小定理を使う
- 拡張ユークリッド互除法を使う
どちらも計算量はとなる。前者の場合、Fermatの小定理からaの逆元はとなる。は上の累乗を求めるアルゴリズムを用いてで求められる。したがって、累乗の逆元を求めたい場合は、累乗を求めて、その逆元を求めればよいので、となる。
二項係数
今回の問題では、なので、の分母、分子はそれぞれで計算できるので間に合う。しかし、aがより大きいとき、階乗を効率的に計算する方法があるのか気になったので調べたところをで計算する方法があるらしい[2]。
参考
- [1]「1000000007 で割ったあまり」の求め方を総特集! 〜 逆元から離散対数まで 〜 https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a
- [2] 階乗 mod 素数 https://min-25.hatenablog.com/entry/2017/04/10/215046