C++の練習を兼ねて, AtCoder Regular Contest 033 の 問題D (見たことのない多項式) を解いてみた.
■感想.
1. 問題Dは, 方針が見えなかったので, 解説を参考に, AC版に到達できたと思う.
2. 個人的には, ラグランジュ補間について, 学習できたので, 非常に良かったと思う.
3. 引き続き, 時間を見つけて, 過去問の学習を進めていきたいと思う.
本家のサイト AtCoder Regular Contest 033 解説 を ご覧下さい.
■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 |
// 解き直し. // https://www.slideshare.net/chokudai/arc033 // C++(GCC 9.2.1) #include <bits/stdc++.h> using namespace std; using LL = long long; #define repex(i, a, b, c) for(int i = a; i < b; i += c) #define repx(i, a, b) repex(i, a, b, 1) #define rep(i, n) repx(i, 0, n) #define repr(i, a, b) for(int i = a; i >= b; i--) const LL MOD = 1e9 + 7; const int MAX = 101010; LL p[MAX], q[MAX], c[MAX], qt[MAX]; // Fermat's little theorem から, 大きな冪乗の計算を行う. // @param a: べき乗したい正整数. // @param b: 指数. // @return: べき乗した計算結果(mod版). LL mPow(LL a, LL b){ LL t = 1; while(b){ if(b & 1) t = (t * a) % MOD; a = a * a % MOD; b >>= 1; } return t; } int main(){ // 1. 入力情報. int N; scanf("%d", &N); rep(i, N + 1) scanf("%lld", &p[i]); LL T; scanf("%lld", &T); // 2. 例外. if(T <= (LL)N){ printf("%lld\n", p[(int)T]); return 0; } // 3. ラグランジュ補間. // Q[i](x) = (x - 0) * (x - 1) * ... * (x - N) / (x - i) // ex. N = 5. // Q[0](0) = (-1) * (-2) * (-3) * (-4) * (-5) // Q[1](1) = (+1) * (-1) * (-2) * (-3) * (-4) // Q[2](2) = (+2) * (+1) * (-1) * (-2) * (-3) // Q[3](3) = (+3) * (+2) * (+1) * (-1) * (-2) // Q[4](4) = (+4) * (+3) * (+2) * (+1) * (-1) // Q[5](5) = (+5) * (+4) * (+3) * (+2) * (+1) // // 3-1. Q[0](0). q[0] = 1; rep(i, N) q[0] = q[0] * (MOD - i - 1) % MOD; // 3-2. Q[1](1) ~ Q[N](N). repx(i, 1, N + 1){ q[i] = q[i - 1]; q[i] *= i; q[i] %= MOD; q[i] *= mPow(MOD + (i - 1 - N), MOD - 2); q[i] %= MOD; } // 3-3. C[i] (= P[i] / Q[i](i)). rep(i, N + 1) c[i] = p[i] * mPow(q[i], MOD - 2) % MOD; // 3-4. 基準. LL b = 1; rep(i, N + 1) b = b * (T - i) % MOD; // 3-5. Q[0](T) ~ Q[N](T). rep(i, N + 1){ qt[i] = b; qt[i] %= MOD; qt[i] *= mPow(T - i, MOD - 2); qt[i] %= MOD; } // 4. P(T). LL ans = 0; rep(i, N + 1) ans = (ans + c[i] * qt[i] % MOD) % MOD; // 5. 出力. printf("%lld\n", ans); return 0; } |
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 |
[入力例] 2 1 3 7 3 [出力例] 13 ※AtCoderテストケースより [入力例] 5 4 16 106 484 1624 4384 1000000000 [出力例] 999984471 ※AtCoderテストケースより [入力例] 1 1 2 1 [出力例] 2 [入力例] 1 1 2 3 [出力例] 4 [入力例] 2 1 2 3 5 [出力例] 6 [入力例] 3 3 2 1 3 7 [出力例] 101 [入力例] 6 3 1 4 1 5 9 2 10 [出力例] 5440 [入力例] 10 3 9 0 8 5 2 9 10 9 1 10 15 [出力例] 1156402 [入力例] 30 3 5 4 6 0 8 9 2 0 3 1 5 7 8 0 3 7 2 1 6 9 10 9 8 2 3 1 8 7 10 7 32 [出力例] 812509535 |
■参照サイト
AtCoder Regular Contest 033