結果
問題 | No.2503 Typical Path Counting Problem on a Grid |
ユーザー | Misuki |
提出日時 | 2024-03-13 13:56:48 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 369 ms / 2,000 ms |
コード長 | 8,836 bytes |
コンパイル時間 | 2,756 ms |
コンパイル使用メモリ | 205,616 KB |
実行使用メモリ | 42,612 KB |
最終ジャッジ日時 | 2024-09-29 22:51:27 |
合計ジャッジ時間 | 5,840 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 66 ms
42,448 KB |
testcase_01 | AC | 109 ms
42,404 KB |
testcase_02 | AC | 86 ms
42,368 KB |
testcase_03 | AC | 196 ms
42,368 KB |
testcase_04 | AC | 305 ms
42,612 KB |
testcase_05 | AC | 163 ms
42,408 KB |
testcase_06 | AC | 369 ms
42,408 KB |
testcase_07 | AC | 361 ms
42,496 KB |
testcase_08 | AC | 229 ms
42,496 KB |
testcase_09 | AC | 306 ms
42,380 KB |
ソースコード
#pragma GCC optimize("O2") #include <algorithm> #include <array> #include <bit> #include <bitset> #include <cassert> #include <cctype> #include <cfenv> #include <cfloat> #include <chrono> #include <cinttypes> #include <climits> #include <cmath> #include <compare> #include <complex> #include <concepts> #include <cstdarg> #include <cstddef> #include <cstdint> #include <cstdio> #include <cstdlib> #include <cstring> #include <deque> #include <fstream> #include <functional> #include <initializer_list> #include <iomanip> #include <ios> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <map> #include <memory> #include <new> #include <numbers> #include <numeric> #include <ostream> #include <queue> #include <random> #include <ranges> #include <set> #include <span> #include <sstream> #include <stack> #include <streambuf> #include <string> #include <tuple> #include <type_traits> #include <variant> //#define int ll #define INT128_MAX (__int128)(((unsigned __int128) 1 << ((sizeof(__int128) * __CHAR_BIT__) - 1)) - 1) #define INT128_MIN (-INT128_MAX - 1) #define clock chrono::steady_clock::now().time_since_epoch().count() #ifdef DEBUG #define dbg(x) cout << (#x) << " = " << x << '\n' #else #define dbg(x) #endif namespace R = std::ranges; namespace V = std::views; using namespace std; using ll = long long; using ull = unsigned long long; using ldb = long double; using pii = pair<int, int>; using pll = pair<ll, ll>; //#define double ldb template<class T> ostream& operator<<(ostream& os, const pair<T, T> pr) { return os << pr.first << ' ' << pr.second; } template<class T, size_t N> ostream& operator<<(ostream& os, const array<T, N> &arr) { for(const T &X : arr) os << X << ' '; return os; } template<class T> ostream& operator<<(ostream& os, const vector<T> &vec) { for(const T &X : vec) os << X << ' '; return os; } template<class T> ostream& operator<<(ostream& os, const set<T> &s) { for(const T &x : s) os << x << ' '; return os; } //reference: https://github.com/NyaanNyaan/library/blob/master/modint/montgomery-modint.hpp#L10 //note: mod should be a prime less than 2^30. template<uint32_t mod> struct MontgomeryModInt { using mint = MontgomeryModInt; using i32 = int32_t; using u32 = uint32_t; using u64 = uint64_t; static constexpr u32 get_r() { u32 res = 1, base = mod; for(i32 i = 0; i < 31; i++) res *= base, base *= base; return -res; } static constexpr u32 get_mod() { return mod; } static constexpr u32 n2 = -u64(mod) % mod; //2^64 % mod static constexpr u32 r = get_r(); //-P^{-1} % 2^32 u32 a; static u32 reduce(const u64 &b) { return (b + u64(u32(b) * r) * mod) >> 32; } static u32 transform(const u64 &b) { return reduce(u64(b) * n2); } MontgomeryModInt() : a(0) {} MontgomeryModInt(const int64_t &b) : a(transform(b % mod + mod)) {} mint pow(u64 k) const { mint res(1), base(*this); while(k) { if (k & 1) res *= base; base *= base, k >>= 1; } return res; } mint inverse() const { return (*this).pow(mod - 2); } u32 get() const { u32 res = reduce(a); return res >= mod ? res - mod : res; } mint& operator+=(const mint &b) { if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod; return *this; } mint& operator-=(const mint &b) { if (i32(a -= b.a) < 0) a += 2 * mod; return *this; } mint& operator*=(const mint &b) { a = reduce(u64(a) * b.a); return *this; } mint& operator/=(const mint &b) { a = reduce(u64(a) * b.inverse().a); return *this; } mint operator-() { return mint() - mint(*this); } bool operator==(mint b) const { return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a); } bool operator!=(mint b) const { return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a); } friend mint operator+(mint a, mint b) { return a += b; } friend mint operator-(mint a, mint b) { return a -= b; } friend mint operator*(mint a, mint b) { return a *= b; } friend mint operator/(mint a, mint b) { return a /= b; } friend ostream& operator<<(ostream& os, const mint& b) { return os << b.get(); } friend istream& operator>>(istream& is, mint& b) { int64_t val; is >> val; b = mint(val); return is; } }; using mint = MontgomeryModInt<998244353>; //source: KACTL(for det() and inv()) template<class Mint> struct matrix : vector<vector<Mint>> { matrix(int n, int m) : vector<vector<Mint>>(n, vector<Mint>(m, 0)) {} matrix(int n) : vector<vector<Mint>>(n, vector<Mint>(n, 0)) {} int n() const { return ssize(*this); } int m() const { return ssize((*this)[0]); } static matrix I(int n) { auto res = matrix(n, n); for(int i = 0; i < n; i++) res[i][i] = 1; return res; } matrix& operator+=(const matrix &b) { assert(n() == b.n()); assert(m() == b.m()); for(int i = 0; i < n(); i++) for(int j = 0; j < m(); j++) (*this)[i][j] += b[i][j]; return *this; } matrix& operator-=(const matrix &b) { assert(n() == b.n()); assert(m() == b.m()); for(int i = 0; i < n(); i++) for(int j = 0; j < m(); j++) (*this)[i][j] -= b[i][j]; return *this; } matrix& operator*=(const matrix &b) { assert(m() == b.n()); auto res = matrix(n(), b.m()); for(int i = 0; i < n(); i++) for(int j = 0; j < b.m(); j++) for(int k = 0; k < m(); k++) res[i][j] += (*this)[i][k] * b[k][j]; this -> swap(res); return *this; } matrix pow(ll k) const { assert(n() == m()); auto res = I(n()), base = *this; while(k) { if (k & 1) res *= base; base *= base, k >>= 1; } return res; } Mint det() const { Mint res = 1; auto a = *this; for(int i = 0; i < n(); i++) { for(int j = i + 1; j < m(); j++) { while(a[j][i] != 0) { Mint t = a[i][i] / a[j][i]; if (t != 0) for(int k = i; k < n(); k++) a[i][k] -= a[j][k] * t; swap(a[i], a[j]); res = -res; } } res *= a[i][i]; if (res == 0) return 0; } return res; } matrix inv() const { assert(n() == m()); matrix a = *this, tmp = I(n()); vector<int> col(n()); for(int i = 0; i < n(); i++) col[i] = i; for(int i = 0; i < n(); i++) { int r = i, c = i; for(int j = i; j < n(); j++) { for(int k = i; k < n(); k++) { if (a[j][k] != 0) { r = j, c = k; goto found; } } } return matrix(0); found: a[i].swap(a[r]), tmp[i].swap(tmp[r]); for(int j = 0; j < n(); j++) swap(a[j][i], a[j][c]), swap(tmp[j][i], tmp[j][c]); swap(col[i], col[c]); Mint v = 1 / a[i][i]; for(int j = i + 1; j < n(); j++) { Mint f = a[j][i] * v; a[j][i] = 0; for(int k = i + 1; k < n(); k++) a[j][k] -= f * a[i][k]; for(int k = 0; k < n(); k++) tmp[j][k] -= f * tmp[i][k]; } for(int j = i + 1; j < n(); j++) a[i][j] *= v; for(int j = 0; j < n(); j++) tmp[i][j] *= v; a[i][i] = 1; } for(int i = n() - 1; i > 0; i--) { for(int j = 0; j < i; j++) { Mint v = a[j][i]; for(int k = 0; k < n(); k++) tmp[j][k] -= v * tmp[i][k]; } } for(int i = 0; i < n(); i++) for(int j = 0; j < n(); j++) a[col[i]][col[j]] = tmp[i][j]; return a; } matrix operator-() { return matrix(n(), m()) - (*this); } friend matrix operator+(matrix a, matrix b) { return a += b; } friend matrix operator-(matrix a, matrix b) { return a -= b; } friend matrix operator*(matrix a, matrix b) { return a *= b; } friend ostream& operator<<(ostream& os, const matrix& b) { for(int i = 0; i < b.n(); i++) { os << '\n'; for(int j = 0; j < b.m(); j++) os << b[i][j] << ' '; } return os; } friend istream& operator>>(istream& is, matrix& b) { for(int i = 0; i < b.n(); i++) for(int j = 0; j < b.m(); j++) is >> b[i][j]; return is; } }; const int MAX = 10000001; mint f[MAX]; signed main() { ios::sync_with_stdio(false), cin.tie(NULL); f[0] = 1, f[1] = 2; for(int i = 2; i < MAX; i++) f[i] = f[i - 1] * (2 * i) + f[i - 2] * (i - 1); int t; cin >> t; while(t--) { ll n, m; cin >> n >> m; if (min(n, m) == 0) { cout << 1 << '\n'; continue; } if (n > m) swap(n, m); matrix<mint> M(2, 2), x(2, 1); M[0][1] = 1, M[1][0] = n, M[1][1] = 2 * n + 1; x[0][0] = f[n - 1], x[1][0] = f[n]; auto b = M.pow(m - n) * x; cout << f[n] * b[1][0] + f[n - 1] * b[0][0] * n << '\n'; } return 0; }