結果

問題 No.2413 Multiple of 99
ユーザー KumaTachiRenKumaTachiRen
提出日時 2023-08-11 23:18:31
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
TLE  
実行時間 -
コード長 8,404 bytes
コンパイル時間 5,072 ms
コンパイル使用メモリ 289,276 KB
実行使用メモリ 91,988 KB
最終ジャッジ日時 2024-04-29 14:29:13
合計ジャッジ時間 14,606 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 3 ms
5,248 KB
testcase_01 AC 3 ms
5,376 KB
testcase_02 AC 33 ms
5,760 KB
testcase_03 AC 3 ms
5,376 KB
testcase_04 TLE -
testcase_05 -- -
testcase_06 -- -
testcase_07 -- -
testcase_08 -- -
testcase_09 -- -
testcase_10 -- -
testcase_11 -- -
testcase_12 -- -
testcase_13 -- -
testcase_14 -- -
testcase_15 -- -
testcase_16 -- -
testcase_17 -- -
testcase_18 -- -
testcase_19 -- -
testcase_20 -- -
testcase_21 -- -
testcase_22 -- -
testcase_23 -- -
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
#include <atcoder/all>

using namespace std;
using namespace atcoder;

struct Fast {
  Fast() {
    std::cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << setprecision(10);
  }
} fast;

#define popcount(x) __builtin_popcount(x)
#define all(a) (a).begin(), (a).end()
#define contains(a, x) ((a).find(x) != (a).end())
#define rep(i, a, b) for (int i = (a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (a); i--)
#define writejoin(s, a) rep(_i, 0, (a).size()) cout << (a)[_i] << (_i + 1 < (int)(a).size() ? s : "\n");
#define YN(b) cout << ((b) ? "YES" : "NO") << "\n";
#define Yn(b) cout << ((b) ? "Yes" : "No") << "\n";
#define yn(b) cout << ((b) ? "yes" : "no") << "\n";

using ll = long long;
using mint = modint998244353;

template <typename mint>
class Factorial {
 public:
  Factorial(int max) : n(max) {
    f = vector<mint>(n + 1);
    finv = vector<mint>(n + 1);
    f[0] = 1;
    for (int i = 1; i <= n; i++) f[i] = f[i - 1] * i;
    finv[n] = f[n].inv();
    for (int i = n; i > 0; i--) finv[i - 1] = finv[i] * i;
  }
  mint fact(int k) {
    assert(0 <= k && k <= n);
    return f[k];
  }
  mint fact_inv(int k) {
    assert(0 <= k && k <= n);
    return finv[k];
  }
  mint binom(int k, int r) {
    assert(0 <= k && k <= n);
    if (r < 0 || r > k) return 0;
    return f[k] * finv[r] * finv[k - r];
  }
  mint inv(int k) {
    assert(0 < k && k <= n);
    return finv[k] * f[k - 1];
  }

 private:
  int n;
  vector<mint> f, finv;
};

template <typename mint>
struct FormalPowerSeries : vector<mint> {
  using vector<mint>::vector;
  using FPS = FormalPowerSeries;
  FPS &operator+=(const FPS &r) {
    if (r.size() > this->size()) this->resize(r.size());
    for (int i = 0; i < (int)r.size(); i++) (*this)[i] += r[i];
    return *this;
  }
  FPS &operator+=(const mint &r) {
    if (this->empty()) this->resize(1);
    (*this)[0] += r;
    return *this;
  }
  FPS &operator-=(const FPS &r) {
    if (r.size() > this->size()) this->resize(r.size());
    for (int i = 0; i < (int)r.size(); i++) (*this)[i] -= r[i];
    return *this;
  }
  FPS &operator-=(const mint &r) {
    if (this->empty()) this->resize(1);
    (*this)[0] -= r;
    return *this;
  }
  FPS &operator*=(const mint &v) {
    for (int k = 0; k < (int)this->size(); k++) (*this)[k] *= v;
    return *this;
  }
  FPS &operator*=(const FPS &r) {
    auto c = convolution<mint>((*this), r);
    this->resize(c.size());
    for (int i = 0; i < (int)c.size(); i++) (*this)[i] = c[i];
    return *this;
  }
  FPS &operator/=(const FPS &r) {
    if (this->size() < r.size()) {
      this->clear();
      return *this;
    }
    int n = this->size() - r.size() + 1;
    if ((int)r.size() <= 64) {
      FPS f(*this), g(r);
      g.shrink();
      mint coeff = g.at(g.size() - 1).inv();
      for (auto &x : g) x *= coeff;
      int deg = (int)f.size() - (int)g.size() + 1;
      int gs = g.size();
      FPS quo(deg);
      for (int i = deg - 1; i >= 0; i--) {
        quo[i] = f[i + gs - 1];
        for (int j = 0; j < gs; j++) f[i + j] -= quo[i] * g[j];
      }
      *this = quo * coeff;
      this->resize(n, mint(0));
      return *this;
    }
    return *this = ((*this).rev().pre(n) * r.rev().inv(n)).pre(n).rev();
  }
  FPS &operator%=(const FPS &r) {
    *this -= *this / r * r;
    shrink();
    return *this;
  }
  FPS operator+(const FPS &r) const { return FPS(*this) += r; }
  FPS operator+(const mint &v) const { return FPS(*this) += v; }
  FPS operator-(const FPS &r) const { return FPS(*this) -= r; }
  FPS operator-(const mint &v) const { return FPS(*this) -= v; }
  FPS operator*(const FPS &r) const { return FPS(*this) *= r; }
  FPS operator*(const mint &v) const { return FPS(*this) *= v; }
  FPS operator/(const FPS &r) const { return FPS(*this) /= r; }
  FPS operator%(const FPS &r) const { return FPS(*this) %= r; }
  FPS operator-() const {
    FPS ret(this->size());
    for (int i = 0; i < (int)this->size(); i++) ret[i] = -(*this)[i];
    return ret;
  }
  void shrink() {
    while (this->size() && this->back() == mint(0)) this->pop_back();
  }
  FPS rev() const {
    FPS ret(*this);
    reverse(begin(ret), end(ret));
    return ret;
  }
  FPS dot(FPS r) const {
    FPS ret(min(this->size(), r.size()));
    for (int i = 0; i < (int)ret.size(); i++) ret[i] = (*this)[i] * r[i];
    return ret;
  }
  FPS pre(int sz) const {
    return FPS(begin(*this), begin(*this) + min((int)this->size(), sz));
  }
  FPS operator>>(int sz) const {
    if ((int)this->size() <= sz) return {};
    FPS ret(*this);
    ret.erase(ret.begin(), ret.begin() + sz);
    return ret;
  }
  FPS operator<<(int sz) const {
    FPS ret(*this);
    ret.insert(ret.begin(), sz, mint(0));
    return ret;
  }
  FPS diff() const {
    const int n = (int)this->size();
    FPS ret(max(0, n - 1));
    mint one(1), coeff(1);
    for (int i = 1; i < n; i++) {
      ret[i - 1] = (*this)[i] * coeff;
      coeff += one;
    }
    return ret;
  }
  FPS integral() const {
    const int n = (int)this->size();
    FPS ret(n + 1);
    ret[0] = mint(0);
    if (n > 0) ret[1] = mint(1);
    auto mod = mint::get_mod();
    for (int i = 2; i <= n; i++) ret[i] = (-ret[mod % i]) * (mod / i);
    for (int i = 0; i < n; i++) ret[i + 1] *= (*this)[i];
    return ret;
  }
  mint eval(mint x) const {
    mint r = 0, w = 1;
    for (auto &v : *this) r += w * v, w *= x;
    return r;
  }
  FPS log(int deg = -1) const {
    assert((*this)[0] == mint(1));
    if (deg == -1) deg = (int)this->size();
    return (this->diff() * this->inv(deg)).pre(deg - 1).integral();
  }
  FPS pow(int64_t k, int deg = -1) const {
    const int n = (int)this->size();
    if (deg == -1) deg = n;
    if (k == 0) {
      FPS ret(deg);
      if (deg) ret[0] = 1;
      return ret;
    }
    for (int i = 0; i < n; i++) {
      if ((*this)[i] != mint(0)) {
        mint rev = mint(1) / (*this)[i];
        FPS ret = (((*this * rev) >> i).log(deg) * k).exp(deg);
        ret *= (*this)[i].pow(k);
        ret = (ret << (i * k)).pre(deg);
        if ((int)ret.size() < deg) ret.resize(deg, mint(0));
        return ret;
      }
      if (__int128_t(i + 1) * k >= deg) return FPS(deg, mint(0));
    }
    return FPS(deg, mint(0));
  }
  FPS inv(int deg = -1) const {
    assert((*this)[0] != mint(0));
    if (deg == -1) deg = (*this).size();
    FPS ret{mint(1) / (*this)[0]};
    for (int i = 1; i < deg; i <<= 1)
      ret = (ret + ret - ret * ret * (*this).pre(i << 1)).pre(i << 1);
    return ret.pre(deg);
  }
  FPS exp(int deg = -1) const {
    assert((*this)[0] == mint(0));
    if (deg == -1) deg = (*this).size();
    FPS ret{mint(1)};
    for (int i = 1; i < deg; i <<= 1)
      ret = (ret * ((*this).pre(i << 1) - ret.log(i << 1) + 1)).pre(i << 1);
    return ret.pre(deg);
  }
};

vector<mint> mul(const vector<mint> &f, const vector<mint> &g) {
  auto h = convolution(f, g);
  rrep(i, 99, h.size()) h[i - 99] += h[i];
  if ((int)h.size() > 99) h.resize(99);
  return h;
}

using fps = FormalPowerSeries<mint>;

fps prod(const vector<pair<mint, mint>> &f, const int deg) {
  if ((int)f.size() == 0) return fps{0};
  queue<fps> q1, q2;
  for (auto e : f) {
    q1.push(fps{e.first});
    q2.push(fps{1, -e.second});
  }
  while (q1.size() > 1) {
    auto u1 = q1.front();
    q1.pop();
    auto u2 = q1.front();
    q1.pop();
    auto v1 = q2.front();
    q2.pop();
    auto v2 = q2.front();
    q2.pop();
    q1.push(u1 * v2 + u2 * v1);
    q2.push(v1 * v2);
  }
  return q1.front() * q2.front().inv(deg);
}

int main() {
  int n, k;
  cin >> n >> k;

  Factorial<mint> fact(100000);

  vector<mint> f{1}, g{1};
  vector<mint> a(10, 1);
  int mf = n / 2;
  int mg = (n + 1) / 2;
  while (mg) {
    if (mf & 1) f = convolution(f, a);
    if (mg & 1) g = convolution(g, a);
    a = convolution(a, a);
    mf /= 2;
    mg /= 2;
  }

  using P = pair<mint, mint>;
  vector<vector<mint>> fr(99, vector<mint>(k + 1)), gr(99, vector<mint>(k + 1));
  rep(r, 0, 99) {
    vector<P> fs, gs;
    for (int v = r; v < (int)f.size(); v += 99) fs.push_back(P{f[v], v});
    for (int v = r; v < (int)g.size(); v += 99) gs.push_back(P{g[v], v});
    fr[r] = prod(fs, k + 1);
    fr[r].resize(k + 1);
    gr[r] = prod(gs, k + 1);
    gr[r].resize(k + 1);
  }

  mint ans = 0;
  rep(i, 0, k + 1) rep(v, 0, 99) ans += fact.binom(k, i) * fr[v][i] * gr[(99 - v) * 10 % 99][k - i];
  cout << ans.val() << "\n";
}
0