結果
問題 | No.2459 Stampaholic (Hard) |
ユーザー |
![]() |
提出日時 | 2023-09-01 23:31:14 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 567 ms / 4,000 ms |
コード長 | 9,022 bytes |
コンパイル時間 | 6,119 ms |
コンパイル使用メモリ | 329,112 KB |
実行使用メモリ | 29,588 KB |
最終ジャッジ日時 | 2025-01-03 12:38:14 |
合計ジャッジ時間 | 13,386 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 19 |
ソースコード
#if __INCLUDE_LEVEL__ == 0#include <bits/stdc++.h>using namespace std;#include __BASE_FILE__namespace {Comb<Fp> comb(1e6);void solve() {int h, w, n, k;cin >> tie(h, w, n, k);vector<Fp> pw(n + 1, 1);for (int i : rep(n)) {pw[i + 1] = pw[i] * (h - k + 1) * (w - k + 1);}int mh = min(k, h - k + 1);int mw = min(k, w - k + 1);int lh = abs(h - k * 2 + 1) + 1;int lw = abs(w - k * 2 + 1) + 1;vector<Fp> denom(n + 1);for (int i : rep1(0, n)) {denom[i] = comb.recip_fact(i + 1);}denom = inv(denom);vector<Fp> sh(n + 1);for (int i : rep1(0, n)) {sh[i] = (Fp(mh).pow(i + 1) - 1) * comb.recip_fact(i + 1);}sh *= denom;for (int i : rep1(0, n)) {sh[i] *= comb.fact(i);}vector<Fp> sw(n + 1);for (int i : rep1(0, n)) {sw[i] = (Fp(mw).pow(i + 1) - 1) * comb.recip_fact(i + 1);}sw *= denom;for (int i : rep1(0, n)) {sw[i] *= comb.fact(i);}Fp ans = 0;for (int i : rep1(0, n)) {ans += comb.binom(n, i) * pw[i] * Fp(-1).pow(n - i) * sh[n - i] * sw[n - i];}ans *= 4;for (int i : rep1(0, n)) {ans += comb.binom(n, i) * pw[i] * Fp(-mw).pow(n - i) * sh[n - i] * lw * 2;}for (int i : rep1(0, n)) {ans += comb.binom(n, i) * pw[i] * Fp(-mh).pow(n - i) * sw[n - i] * lh * 2;}ans += (pw[1] - Fp(mh) * mw).pow(n) * lh * lw;ans /= pw[n];ans = Fp(h) * w - ans;print(ans);}} // namespaceint main() {ios::sync_with_stdio(false);cin.tie(nullptr);solve();}#else // __INCLUDE_LEVEL__#undef assert#define assert(expr) (expr) || (__builtin_unreachable(), 0)#include <atcoder/convolution>template <class T>vector<T> make_vector_for_overwrite(int n) {static_assert(is_trivially_destructible_v<T>);vector<T> v;v.reserve(n);auto p = (T**)&v;p[1] = p[2];return v;}template <class T>class Comb {public:Comb() = default;explicit Comb(int max_n): fact_(make_vector_for_overwrite<T>(max_n + 1)),recip_fact_(make_vector_for_overwrite<T>(max_n + 1)) {fact_[0] = 1;for (int n = 1; n <= max_n; ++n) {fact_[n] = fact_[n - 1] * n;}recip_fact_[max_n] = 1 / fact_[max_n];for (int n = max_n; 1 <= n; --n) {recip_fact_[n - 1] = n * recip_fact_[n];}}T recip(int n) const {assert(n);return n < 0 ? -recip(-n) : recip_fact_[n] * fact_[n - 1];}T fact(int n) const {assert(0 <= n);return fact_[n];}T recip_fact(int n) const { return n < 0 ? 0 : recip_fact_[n]; }T falling_fact(int n, int k) const {assert(0 <= n || n < k);if (n < 0) {T t = falling_fact(k - n - 1, k);return k & 1 ? -t : t;}return n < k ? 0 : recip_fact(n - k) * fact(n);}T recip_falling_fact(int n, int k) const {assert(n < 0 || k <= n);return falling_fact(n - k, -k);}T rising_fact(int n, int k) const {assert(n <= 0 || 0 < n + k);return falling_fact(n + k - 1, k);}T recip_rising_fact(int n, int k) const {assert(0 < n || n + k <= 0);return falling_fact(n - 1, -k);}T binom(int n, int k) const {if ((n < 0) ^ (k < 0) ^ (n < k)) {return 0;}if (n < 0 && k < 0) {k = n - k;}return recip_fact(k) * falling_fact(n, k);}T recip_binom(int n, int k) const {assert((0 <= n) ^ (0 <= k) ^ (k <= n));k = max(k, n - k);return recip_falling_fact(n, k) * fact(k);}T multiset(int n, int k) const { return binom(n + k - 1, k); }T recip_multiset(int n, int k) const {assert((0 < n) ^ (0 <= k) ^ (0 < n + k));return recip_binom(n + k - 1, k);}private:vector<T> fact_;vector<T> recip_fact_;};template <class T, class U = T>bool chmin(T& x, U&& y) {return y < x && (x = forward<U>(y), true);}template <class T, class U = T>bool chmax(T& x, U&& y) {return x < y && (x = forward<U>(y), true);}namespace std {template <class T1, class T2>istream& operator>>(istream& is, pair<T1, T2>& p) {return is >> p.first >> p.second;}template <class... Ts>istream& operator>>(istream& is, tuple<Ts...>& t) {return apply([&is](auto&... xs) -> istream& { return (is >> ... >> xs); }, t);}template <class... Ts>istream& operator>>(istream& is, tuple<Ts&...>&& t) {return is >> t;}template <class R, enable_if_t<!is_convertible_v<R, string>>* = nullptr>auto operator>>(istream& is, R&& r) -> decltype(is >> *begin(r)) {for (auto&& e : r) {is >> e;}return is;}template <class T1, class T2>ostream& operator<<(ostream& os, const pair<T1, T2>& p) {return os << p.first << ' ' << p.second;}template <class... Ts>ostream& operator<<(ostream& os, const tuple<Ts...>& t) {auto f = [&os](const auto&... xs) -> ostream& {[[maybe_unused]] auto sep = "";((os << exchange(sep, " ") << xs), ...);return os;};return apply(f, t);}template <class R, enable_if_t<!is_convertible_v<R, string_view>>* = nullptr>auto operator<<(ostream& os, R&& r) -> decltype(os << *begin(r)) {auto sep = "";for (auto&& e : r) {os << exchange(sep, " ") << e;}return os;}} // namespace stdnamespace atcoder {template <class T, internal::is_modint_t<T>* = nullptr>istream& operator>>(istream& is, T& x) {int v;is >> v;x = T::raw(v);return is;}template <class T, internal::is_modint_t<T>* = nullptr>ostream& operator<<(ostream& os, const T& x) {return os << x.val();}} // namespace atcodertemplate <class... Ts>void print(Ts&&... xs) {cout << tie(xs...) << '\n';}inline auto rep(int l, int r) { return views::iota(min(l, r), r); }inline auto rep(int n) { return rep(0, n); }inline auto rep1(int l, int r) { return rep(l, r + 1); }inline auto rep1(int n) { return rep(1, n + 1); }inline auto per(int l, int r) { return rep(l, r) | views::reverse; }inline auto per(int n) { return per(0, n); }inline auto per1(int l, int r) { return per(l, r + 1); }inline auto per1(int n) { return per(1, n + 1); }using Fp = atcoder::modint998244353;using Fps = std::vector<Fp>;int sz(const Fps& a) { return a.size(); }Fps operator-(Fps a) {for (auto&& e : a) e = -e;return a;}Fps& operator+=(Fps& a, const Fps& b) {if (sz(a) < sz(b)) a.reserve(sz(b)), a.resize(sz(b));for (int i = 0; i < sz(b); ++i) a[i] += b[i];return a;}Fps operator+(Fps a, const Fps& b) { return std::move(a += b); }Fps& operator-=(Fps& a, const Fps& b) {if (sz(a) < sz(b)) a.reserve(sz(b)), a.resize(sz(b));for (int i = 0; i < sz(b); ++i) a[i] -= b[i];return a;}Fps operator-(Fps a, const Fps& b) { return std::move(a -= b); }Fps& operator*=(Fps& a, Fp b) {for (auto&& e : a) e *= b;return a;}Fps operator*(Fps a, Fp b) { return std::move(a *= b); }Fps operator*(Fp a, Fps b) { return std::move(b *= a); }Fps& operator/=(Fps& a, Fp b) {b = b.inv();for (auto&& e : a) e *= b;return a;}Fps operator/(Fps a, Fp b) { return std::move(a /= b); }Fps fft(const Fps& a, int n) {Fps res(n);std::copy(a.begin(), a.begin() + std::min(n, sz(a)), res.begin());atcoder::internal::butterfly(res);return res;}Fps circ(Fps&& a, const Fps& b) {if (sz(a) < sz(b)) a.reserve(sz(b)), a.resize(sz(b));for (int i = 0; i < sz(b); ++i) a[i] *= b[i];return a;}Fps circ(Fps&& a) {for (auto&& e : a) e *= e;return a;}Fps ifft(Fps&& a, int size) {int n = sz(a);atcoder::internal::butterfly_inv(a);a.resize(size);a *= (1 - Fp::mod()) / n;return a;}Fps operator*(const Fps& a, const Fps& b) {if (a.empty() || b.empty()) return {};if (std::min(sz(a), sz(b)) <= 60) {Fps res(std::max(sz(a), sz(b)));for (int i = 0; i < sz(a); ++i)for (int j = 0; j < sz(b); ++j) {if (i + j == sz(res)) break;res[i + j] += a[i] * b[j];}return res;}int n = __bit_ceil(sz(a) + sz(b) - 1);auto buf = fft(a, n);if (&a == &b)buf = circ(std::move(buf));elsebuf = circ(std::move(buf), fft(b, n));return ifft(std::move(buf), std::max(sz(a), sz(b)));}Fps& operator*=(Fps& a, const Fps& b) { return a = a * b; }Fps inv(const Fps& a) {Fps res{a[0].inv()};for (int n = 1; n < sz(a); n *= 2) {auto f_res = fft(res, 2 * n);Fps buf = ifft(circ(fft(a, 2 * n), f_res), 2 * n);std::fill(buf.begin(), buf.begin() + n, 0);buf = ifft(circ(fft(buf, 2 * n), f_res), std::min(2 * n, sz(a)));for (int i = n; i < sz(buf); ++i) res.push_back(-buf[i]);}return res;}Fps deriv(const Fps& a) {Fps res(sz(a));for (int i = 1; i < sz(a); ++i) res[i - 1] = a[i] * i;return res;}Fps integ(const Fps& a) {Fps res(sz(a));for (int i = 1; i < sz(res); ++i) res[i] = a[i - 1] / i;return res;}Fps log(const Fps& a) { return integ(deriv(a) * inv(a)); }Fps exp(const Fps& a) {Fps res{1};for (res.reserve(sz(a)); sz(res) < sz(a);) {res.resize(std::min(2 * sz(res), sz(a)));res *= Fps{1} - log(res) + Fps(a.begin(), a.begin() + sz(res));}return res;}#endif // __INCLUDE_LEVEL__