結果
| 問題 |
No.2396 等差二項展開
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2023-02-24 03:06:28 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,022 ms / 6,000 ms |
| コード長 | 2,145 bytes |
| コンパイル時間 | 3,691 ms |
| コンパイル使用メモリ | 254,036 KB |
| 最終ジャッジ日時 | 2025-02-10 20:11:15 |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 31 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
#include <atcoder/all>
using namespace atcoder;
using mint = modint;
//【畳込み】O(n m)
/*
* a[0..n) と b[0..m) を畳み込んだ数列 c[0..n+m-1) を返す.
*/
vector<mint> naive_convolution(const vector<mint>& a, const vector<mint>& b) {
int n = (int)a.size(), m = (int)b.size();
// c[i] = Σj∈[0..i] a[j] b[i-j] (∀i∈[0..n+m-1))
vector<mint> c(n + m - 1);
for (int i = 0; i < n + m - 1; i++) {
for (int j = max(i - (m - 1), 0); j <= min(i, n - 1); j++) {
c[i] += a[j] * b[i - j];
}
}
return c;
}
//【テプリッツ行列の累乗】O(n^2 log d)
/*
* 左下から右上までの成分が順に a(-n..n) であるテプリッツ行列を d 乗したテプリッツ行列を返す.
*/
vector<mint> toeplitz_pow(const vector<mint>& a, long long d) {
int n = ((int)a.size() + 1) / 2;
// テプリッツ行列 a, b の積を返す(制約 : 結果もテプリッツ行列)
auto mul = [&](const vector<mint>& a, const vector<mint>& b) {
vector<mint> bl(n), br(n);
for (int i = 0; i < n; i++) bl[i] = b[i];
for (int i = 0; i < n; i++) br[i] = b[n - 1 + i];
auto resl = naive_convolution(a, bl);
auto resr = naive_convolution(a, br);
vector<mint> res(2 * n - 1);
for (int i = 0; i < n; i++) res[i] = resl[n - 1 + i];
for (int i = 1; i < n; i++) res[n - 1 + i] = resr[n - 1 + i];
return res;
};
vector<mint> res(2 * n - 1), pow2 = a;
res[n - 1] = 1;
// ダブリングでテプリッツ行列を累乗する.
while (d > 0) {
if ((d & 1) != 0) {
res = mul(res, pow2);
}
pow2 = mul(pow2, pow2);
d /= 2;
}
return res;
}
int main() {
// input_from_file("input.txt");
// output_to_file("output.txt");
long long n, m; int l, k, b;
cin >> n >> m >> l >> k >> b;
mint::set_mod(b);
// l = 1 のときは二項定理で OK
if (l == 1) {
cout << mint(1 + m).pow(n).val() << endl;
return 0;
}
// mat : 遷移行列(テプリッツ行列)
vector<mint> mat(2 * l - 1);
mat[0] = m; mat[l - 1] = mat[l] = 1;
// n 回遷移する
mat = toeplitz_pow(mat, n);
cout << mat[l - 1 + k].val() << endl;
}