C++の練習を兼ねて, AtCoder Beginner Contest 110 の 問題D (D – Factorization) を解いてみた.
■感想.
1. 数え上げについて, 解答方針が全く見えなかったので, 解説を丸写しする感覚で解き直しした.
2. 数え上げに必要なライブラリが, 正常に動作していることの確認も出来たので良かったと思う.
本家のサイトABC 110解説をご覧下さい.
■C++版プログラム(問題D/AC版).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
// ABC 110解説 // https://img.atcoder.jp/abc110/editorial.pdf #include <bits/stdc++.h> using namespace std; using LL = long long; const LL MOD = 1e9 + 7; const LL MAX = 123456; LL F[MAX]; LL IF[MAX]; // Efficient program to print all prime factors of a given number // https://www.geeksforgeeks.org/print-all-prime-factors-of-a-given-number/ // 与えられた正整数についての素因数分解を計算. // @param X: 素因数分解を行う整数. // @return ret: 素因数分解 の 結果 を 返却. map<LL, LL> div(LL X) { // 1. X を 2で割り切れなくなるまで割っていく. map<LL, LL> ret; while(X % 2 == 0) ret[2]++, X >>= 1; // 2. X を 3以上の奇数で, 割り切れなくなるまで順次割っていく. for(LL i = 3; i <= sqrt(X); i += 2){ while(X % i == 0){ ret[i]++; X /= i; } } // 3. X が 2 より 大きな素数であれば, 追加. if(X > 2) ret[X]++; // 4. 出力. return ret; } // Fermat's little theorem を 適用するため, ap-2乗 などを計算できるようにする. // @param a: べき乗したい正整数. // @param b: 指数. // @return: べき乗した計算結果(mod版). LL inverse(LL a, LL b){ LL t = 1; while(b) { if(b & 1) t = (t * a) % MOD; a *= a; a %= MOD; b >>= 1; } return t % MOD; } // 配列 IF に, 逆元を保存. // @param: 特に無し. // @return: 配列IF の update. void initialize(){ F[0] = 1, IF[0] = 1; for(LL i = 1; i < MAX; i++){ F[i] = (F[i - 1] * i) % MOD; //逆元を、フェルマーの小定理を利用して求める IF[i] = inverse(F[i], MOD - 2) % MOD; } } // 組み合わせ(nCk)計算用(mod版). // ※配列F, IF は, 事前に計算済のものを使う. // @param n: 対象となる要素の個数. // @param k: 選択する要素の個数. // @return: 組み合わせ(nCk)の計算結果. LL combination(LL n, LL k){ if(n < 0 || k < 0 || k > n) return 0; LL ret = F[n] * IF[k] % MOD * IF[n - k] % MOD; return ret; } int main() { // 1. 入力情報取得. LL N, M; cin >> N >> M; initialize(); // 2. 素因数分解. map<LL, LL> m = div(M); // for(auto &p : m) cout << "p.first=" << p.first << " p.second=" << p.second << endl; // 3. 場合の数をカウント. // -> 解説通り. LL ans = 1; for(auto &p : m) ans *= combination(p.second + N - 1, p.second), ans %= MOD; // 4. 出力 ~ 後処理. cout << ans << endl; return 0; } |
■参照サイト
AtCoder Beginner Contest 110