Problem p02635 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
using namespace std;

// template {{{
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define lb lower_bound
#define ub upper_bound
#define f first
#define s second
#define resz resize

#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, a) for (int i = 0; i < (a); i++)
#define FORd(i, a, b) for (int i = (b)-1; i >= (a); i--)
#define F0Rd(i, a) for (int i = (a)-1; i >= 0; i--)
#define trav(a, x) for (auto &a : x)

#define sort_by(x, y)                                                          \\
  sort(all(x), [&](const auto &a, const auto &b) { return y; })

using ll = long long;
using ld = long double;
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vb = vector<bool>;
using vd = vector<double>;
using vs = vector<string>;

using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdd = pair<double, double>;

using vpii = vector<pii>;
using vvpii = vector<vpii>;
using vpll = vector<pll>;
using vvpll = vector<vpll>;
using vpdd = vector<pdd>;
using vvpdd = vector<vpdd>;

template <typename T> void ckmin(T &a, const T &b) { a = min(a, b); }
template <typename T> void ckmax(T &a, const T &b) { a = max(a, b); }

template <typename T> using max_heap = priority_queue<T>;
template <typename T> using min_heap = priority_queue<T, vector<T>, greater<T>>;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

namespace __input {
template <class T1, class T2> void re(pair<T1, T2> &p);
template <class T> void re(vector<T> &a);
template <class T, size_t SZ> void re(array<T, SZ> &a);

template <class T> void re(T &x) { cin >> x; }
void re(double &x) {
  string t;
  re(t);
  x = stod(t);
}
template <class Arg, class... Args> void re(Arg &first, Args &...rest) {
  re(first);
  re(rest...);
}

template <class T1, class T2> void re(pair<T1, T2> &p) { re(p.f, p.s); }
template <class T> void re(vector<T> &a) { F0R(i, sz(a)) re(a[i]); }
template <class T, size_t SZ> void re(array<T, SZ> &a) { F0R(i, SZ) re(a[i]); }
} // namespace __input
using namespace __input;

namespace __output {
template <class T1, class T2> void pr(const pair<T1, T2> &x);
template <class T, size_t SZ> void pr(const array<T, SZ> &x);
template <class T> void pr(const vector<T> &x);
template <class T> void pr(const deque<T> &x);
template <class T> void pr(const set<T> &x);
template <class T1, class T2> void pr(const map<T1, T2> &x);

template <class T> void pr(const T &x) { cout << x; }
template <class Arg, class... Args>
void pr(const Arg &first, const Args &...rest) {
  pr(first);
  pr(rest...);
}

template <class T1, class T2> void pr(const pair<T1, T2> &x) {
  pr("{", x.f, ", ", x.s, "}");
}
template <class T, bool pretty = true> void prContain(const T &x) {
  if (pretty)
    pr("{");
  bool fst = 1;
  for (const auto &a : x)
    pr(!fst ? pretty ? ", " : " " : "", a), fst = 0;
  if (pretty)
    pr("}");
}
template <class T> void pc(const T &x) {
  prContain<T, false>(x);
  pr("\\n");
}
template <class T, size_t SZ> void pr(const array<T, SZ> &x) { prContain(x); }
template <class T> void pr(const vector<T> &x) { prContain(x); }
template <class T> void pr(const deque<T> &x) { prContain(x); }
template <class T> void pr(const set<T> &x) { prContain(x); }
template <class T1, class T2> void pr(const map<T1, T2> &x) { prContain(x); }

void ps() { pr("\\n"); }
template <class Arg> void ps(const Arg &first) {
  pr(first);
  ps();
}
template <class Arg, class... Args>
void ps(const Arg &first, const Args &...rest) {
  pr(first, " ");
  ps(rest...);
}
} // namespace __output
using namespace __output;

#define TRACE(x) x
#define __pn(x) pr(#x, " = ")
#define pd(...) __pn((__VA_ARGS__)), ps(__VA_ARGS__), cout << flush

namespace __numeric {
template <typename T>
typename enable_if<is_integral<T>::value, T>::type floor(T n, T d) {
  assert(d != 0);
  if (d < 0)
    tie(n, d) = mp(-n, -d);
  return n / d - ((n < 0) && (n % d));
}
template <typename T>
typename enable_if<is_integral<T>::value, T>::type ceil(T n, T d) {
  assert(d != 0);
  if (d < 0)
    tie(n, d) = mp(-n, -d);
  return n / d + ((n > 0) && (n % d));
}
}; // namespace __numeric
using namespace __numeric;

namespace __algorithm {
template <typename T> void dedup(vector<T> &v) {
  sort(all(v));
  v.erase(unique(all(v)), v.end());
}
template <typename T>
typename vector<T>::iterator find(vector<T> &v, const T &x) {
  auto it = lower_bound(all(v), x);
  return it != v.end() && *it == x ? it : v.end();
}
template <typename T> size_t index(vector<T> &v, const T &x) {
  auto it = find(v, x);
  assert(it != v.end() && *it == x);
  return it - v.begin();
}
template <typename C, typename T, typename OP>
vector<T> prefixes(const C &v, T id, OP op) {
  vector<T> r(sz(v) + 1, id);
  F0R(i, sz(v)) r[i + 1] = op(r[i], v[i]);
  return r;
}
template <typename C, typename T, typename OP>
vector<T> suffixes(const C &v, T id, OP op) {
  vector<T> r(sz(v) + 1, id);
  F0Rd(i, sz(v)) r[i] = op(v[i], r[i + 1]);
  return r;
}
} // namespace __algorithm
using namespace __algorithm;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
struct monostate {
  friend istream &operator>>(istream &is, const monostate &ms) { return is; }
  friend ostream &operator<<(ostream &os, const monostate &ms) { return os; }
  friend monostate operator+(const monostate &a, const monostate &b) {
    return a;
  }
} ms;
#pragma GCC diagnostic pop

namespace __io {
void setIn(string s) { freopen(s.c_str(), "r", stdin); }
void setOut(string s) { freopen(s.c_str(), "w", stdout); }
void setIO(string s = "") {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout << fixed << setprecision(15);
  if (sz(s)) {
    setIn(s + ".in"), setOut(s + ".out");
  }
}
} // namespace __io
using namespace __io;
// }}}

// modnum {{{
using v_t = int;
using vv_t = ll;
template <v_t MOD> struct modnum {
  v_t v;
  modnum() : v(0) {}
  modnum(vv_t _v) : v(_v % MOD) {
    if (v < 0)
      v += MOD;
  }
  explicit operator v_t() const { return v; }
  friend istream &operator>>(istream &i, modnum &n) {
    vv_t w;
    i >> w;
    n = modnum(w);
    return i;
  }
  friend ostream &operator<<(ostream &o, const modnum &n) { return o << n.v; }

  friend bool operator==(const modnum &a, const modnum &b) {
    return a.v == b.v;
  }
  friend bool operator!=(const modnum &a, const modnum &b) {
    return a.v != b.v;
  }

  static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
#if !defined(_WIN32) || defined(_WIN64)
    return x % m;
#endif
    // x must be less than 2^32 * m so that x / m fits in a 32-bit integer.
    unsigned x_high = x >> 32, x_low = (unsigned)x, quot, rem;
    asm("divl %4\\n" : "=a"(quot), "=d"(rem) : "d"(x_high), "a"(x_low), "r"(m));
    return rem;
  }

  modnum &operator+=(const modnum &o) {
    v += o.v;
    if (v >= MOD)
      v -= MOD;
    return *this;
  }
  modnum &operator-=(const modnum &o) {
    v -= o.v;
    if (v < 0)
      v += MOD;
    return *this;
  }
  modnum &operator*=(const modnum &o) {
    v = fast_mod(vv_t(v) * o.v);
    return *this;
  }
  modnum operator-() {
    modnum res;
    if (v)
      res.v = MOD - v;
    return res;
  }
  friend modnum operator+(const modnum &a, const modnum &b) {
    return modnum(a) += b;
  }
  friend modnum operator-(const modnum &a, const modnum &b) {
    return modnum(a) -= b;
  }
  friend modnum operator*(const modnum &a, const modnum &b) {
    return modnum(a) *= b;
  }

  modnum pow(vv_t e) const {
    if (e < 0)
      return 1 / this->pow(-e);
    if (e == 0)
      return 1;
    if (e & 1)
      return *this * this->pow(e - 1);
    return (*this * *this).pow(e / 2);
  }

  modnum inv() const {
    v_t g = MOD, x = 0, y = 1;
    for (v_t r = v; r != 0;) {
      v_t q = g / r;
      g %= r;
      swap(g, r);
      x -= q * y;
      swap(x, y);
    }

    assert(g == 1);
    assert(y == MOD || y == -MOD);
    return x < 0 ? x + MOD : x;
  }
  modnum &operator/=(const modnum &o) { return (*this) *= o.inv(); }
  friend modnum operator/(const modnum &a, const modnum &b) {
    return modnum(a) /= modnum(b);
  }

  static constexpr v_t totient() {
    v_t tot = MOD, tmp = MOD;
    for (v_t p = 2; p * p <= tmp; p++)
      if (tmp % p == 0) {
        tot = tot / p * (p - 1);
        while (tmp % p == 0)
          tmp /= p;
      }
    if (tmp > 1)
      tot = tot / tmp * (tmp - 1);
    return tot;
  }

  static v_t primitive_root() {
    if (MOD == 1)
      return 0;
    if (MOD == 2)
      return 1;

    v_t tot = totient(), tmp = tot;
    vi tot_pr;
    for (v_t p = 2; p * p <= tmp; p++)
      if (tot % p == 0) {
        tot_pr.push_back(p);
        while (tmp % p == 0)
          tmp /= p;
      }
    if (tmp > 1)
      tot_pr.push_back(tmp);

    for (v_t r = 2; r < MOD; r++)
      if (__gcd(r, MOD) == 1) {
        bool root = true;
        for (v_t p : tot_pr)
          root &= modnum(r).pow(tot / p) != 1;
        if (root)
          return r;
      }
    assert(false);
  }

  static modnum generator() {
    static modnum g = primitive_root();
    return g;
  }
  static v_t discrete_log(modnum v) {
    static const v_t M = ceil(sqrt(MOD));
    static unordered_map<v_t, v_t> table;
    if (table.empty()) {
      modnum e = 1;
      for (v_t i = 0; i < M; i++) {
        table[e.v] = i;
        e *= generator();
      }
    }
    static modnum f = generator().pow(totient() - M);

    for (v_t i = 0; i < M; i++) {
      if (table.count(v.v))
        return table[v.v] + i * M;
      v *= f;
    }
    assert(false);
  }

  static modnum unity_root(int deg) {
    assert(totient() % deg == 0);
    return generator().pow(totient() / deg);
  }

  static modnum unity_root(int deg, int pow) {
    static vector<modnum> table{0, 1};
    while (sz(table) <= deg) {
      modnum w = unity_root(sz(table));
      for (int i = sz(table) / 2, s = sz(table); i < s; i++) {
        table.push_back(table[i]);
        table.push_back(table[i] * w);
      }
    }
    return table[deg + (pow < 0 ? deg + pow : pow)];
  }

  static modnum factorial(int n) {
    static vector<modnum> fact = {1};
    assert(n >= 0);
    if (sz(fact) <= n) {
      int had = sz(fact);
      fact.resize(n + 1);
      for (int i = had; i <= n; i++)
        fact[i] = fact[i - 1] * i;
    }
    return fact[n];
  }
  static modnum inverse_factorial(int n) {
    static vector<modnum> finv = {1};
    assert(n >= 0);
    if (sz(finv) <= n) {
      int had = sz(finv);
      finv.resz(n + 1), finv[n] = factorial(n).inv();
      for (int i = n - 1; i >= had; i--)
        finv[i] = finv[i + 1] * (i + 1);
    }
    return finv[n];
  }

  static modnum small_inv(int n) {
    assert(n > 0);
    return factorial(n - 1) * inverse_factorial(n);
  }

  static modnum ncr(int n, int r) {
    if (r < 0 || n < r)
      return 0;
    return factorial(n) * inverse_factorial(r) * inverse_factorial(n - r);
  }
};
// }}}
using mn = modnum<int(998244353)>;
using vmn = vector<mn>;
using vvmn = vector<vmn>;

int main() {
  setIO();

  string s;
  re(s);
  int K;
  re(K);

  const int N = sz(s);

  reverse(all(s));

  int i = 0;
  while (i < N && s[i] == '1')
    i++;

  vvmn dp(N + 1, vmn(N + 1)), DP = dp;

  F0R(take, i + 1) { dp[take][take] = 1; }

  for (int j = i; i < N; i = j) {
    assert(s[i] == '0');
    j = i + 1;
    while (j < sz(s) && s[j] == '1')
      j++;

    int exist = j - i - 1;

    F0R(x, sz(DP))
    fill(all(DP[x]), 0);

    F0R(have, N + 1) {
      F0R(moves, N + 1) {
        if (!dp[have][moves].v)
          continue;

        F0R(leave, exist + have + 1) {
          DP[exist + have - leave][moves + max(0, exist - leave)] +=
              dp[have][moves];
        }
      }
    }

    swap(dp, DP);
  }

  mn ans = 0;
  F0R(moves, min(N, K) + 1) { ans += dp[0][moves]; }
  ps(ans);

  // did you check N=1? did you mix up N,M?
  // check your "infinity" and "null" values against the bounds
  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;

// template {{{
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define lb lower_bound
#define ub upper_bound
#define f first
#define s second
#define resz resize

#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, a) for (int i = 0; i < (a); i++)
#define FORd(i, a, b) for (int i = (b)-1; i >= (a); i--)
#define F0Rd(i, a) for (int i = (a)-1; i >= 0; i--)
#define trav(a, x) for (auto &a : x)

#define sort_by(x, y)                                                          \\
  sort(all(x), [&](const auto &a, const auto &b) { return y; })

using ll = long long;
using ld = long double;
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vb = vector<bool>;
using vd = vector<double>;
using vs = vector<string>;

using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdd = pair<double, double>;

using vpii = vector<pii>;
using vvpii = vector<vpii>;
using vpll = vector<pll>;
using vvpll = vector<vpll>;
using vpdd = vector<pdd>;
using vvpdd = vector<vpdd>;

template <typename T> void ckmin(T &a, const T &b) { a = min(a, b); }
template <typename T> void ckmax(T &a, const T &b) { a = max(a, b); }

template <typename T> using max_heap = priority_queue<T>;
template <typename T> using min_heap = priority_queue<T, vector<T>, greater<T>>;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

namespace __input {
template <class T1, class T2> void re(pair<T1, T2> &p);
template <class T> void re(vector<T> &a);
template <class T, size_t SZ> void re(array<T, SZ> &a);

template <class T> void re(T &x) { cin >> x; }
void re(double &x) {
  string t;
  re(t);
  x = stod(t);
}
template <class Arg, class... Args> void re(Arg &first, Args &...rest) {
  re(first);
  re(rest...);
}

template <class T1, class T2> void re(pair<T1, T2> &p) { re(p.f, p.s); }
template <class T> void re(vector<T> &a) { F0R(i, sz(a)) re(a[i]); }
template <class T, size_t SZ> void re(array<T, SZ> &a) { F0R(i, SZ) re(a[i]); }
} // namespace __input
using namespace __input;

namespace __output {
template <class T1, class T2> void pr(const pair<T1, T2> &x);
template <class T, size_t SZ> void pr(const array<T, SZ> &x);
template <class T> void pr(const vector<T> &x);
template <class T> void pr(const deque<T> &x);
template <class T> void pr(const set<T> &x);
template <class T1, class T2> void pr(const map<T1, T2> &x);

template <class T> void pr(const T &x) { cout << x; }
template <class Arg, class... Args>
void pr(const Arg &first, const Args &...rest) {
  pr(first);
  pr(rest...);
}

template <class T1, class T2> void pr(const pair<T1, T2> &x) {
  pr("{", x.f, ", ", x.s, "}");
}
template <class T, bool pretty = true> void prContain(const T &x) {
  if (pretty)
    pr("{");
  bool fst = 1;
  for (const auto &a : x)
    pr(!fst ? pretty ? ", " : " " : "", a), fst = 0;
  if (pretty)
    pr("}");
}
template <class T> void pc(const T &x) {
  prContain<T, false>(x);
  pr("\\n");
}
template <class T, size_t SZ> void pr(const array<T, SZ> &x) { prContain(x); }
template <class T> void pr(const vector<T> &x) { prContain(x); }
template <class T> void pr(const deque<T> &x) { prContain(x); }
template <class T> void pr(const set<T> &x) { prContain(x); }
template <class T1, class T2> void pr(const map<T1, T2> &x) { prContain(x); }

void ps() { pr("\\n"); }
template <class Arg> void ps(const Arg &first) {
  pr(first);
  ps();
}
template <class Arg, class... Args>
void ps(const Arg &first, const Args &...rest) {
  pr(first, " ");
  ps(rest...);
}
} // namespace __output
using namespace __output;

#define TRACE(x) x
#define __pn(x) pr(#x, " = ")
#define pd(...) __pn((__VA_ARGS__)), ps(__VA_ARGS__), cout << flush

namespace __numeric {
template <typename T>
typename enable_if<is_integral<T>::value, T>::type floor(T n, T d) {
  assert(d != 0);
  if (d < 0)
    tie(n, d) = mp(-n, -d);
  return n / d - ((n < 0) && (n % d));
}
template <typename T>
typename enable_if<is_integral<T>::value, T>::type ceil(T n, T d) {
  assert(d != 0);
  if (d < 0)
    tie(n, d) = mp(-n, -d);
  return n / d + ((n > 0) && (n % d));
}
}; // namespace __numeric
using namespace __numeric;

namespace __algorithm {
template <typename T> void dedup(vector<T> &v) {
  sort(all(v));
  v.erase(unique(all(v)), v.end());
}
template <typename T>
typename vector<T>::iterator find(vector<T> &v, const T &x) {
  auto it = lower_bound(all(v), x);
  return it != v.end() && *it == x ? it : v.end();
}
template <typename T> size_t index(vector<T> &v, const T &x) {
  auto it = find(v, x);
  assert(it != v.end() && *it == x);
  return it - v.begin();
}
template <typename C, typename T, typename OP>
vector<T> prefixes(const C &v, T id, OP op) {
  vector<T> r(sz(v) + 1, id);
  F0R(i, sz(v)) r[i + 1] = op(r[i], v[i]);
  return r;
}
template <typename C, typename T, typename OP>
vector<T> suffixes(const C &v, T id, OP op) {
  vector<T> r(sz(v) + 1, id);
  F0Rd(i, sz(v)) r[i] = op(v[i], r[i + 1]);
  return r;
}
} // namespace __algorithm
using namespace __algorithm;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
struct monostate {
  friend istream &operator>>(istream &is, const monostate &ms) { return is; }
  friend ostream &operator<<(ostream &os, const monostate &ms) { return os; }
  friend monostate operator+(const monostate &a, const monostate &b) {
    return a;
  }
} ms;
#pragma GCC diagnostic pop

namespace __io {
void setIn(string s) { freopen(s.c_str(), "r", stdin); }
void setOut(string s) { freopen(s.c_str(), "w", stdout); }
void setIO(string s = "") {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout << fixed << setprecision(15);
  if (sz(s)) {
    setIn(s + ".in"), setOut(s + ".out");
  }
}
} // namespace __io
using namespace __io;
// }}}

// modnum {{{
using v_t = int;
using vv_t = ll;
template <v_t MOD> struct modnum {
  v_t v;
  modnum() : v(0) {}
  modnum(vv_t _v) : v(_v % MOD) {
    if (v < 0)
      v += MOD;
  }
  explicit operator v_t() const { return v; }
  friend istream &operator>>(istream &i, modnum &n) {
    vv_t w;
    i >> w;
    n = modnum(w);
    return i;
  }
  friend ostream &operator<<(ostream &o, const modnum &n) { return o << n.v; }

  friend bool operator==(const modnum &a, const modnum &b) {
    return a.v == b.v;
  }
  friend bool operator!=(const modnum &a, const modnum &b) {
    return a.v != b.v;
  }

  static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
#if !defined(_WIN32) || defined(_WIN64)
    return x % m;
#endif
    // x must be less than 2^32 * m so that x / m fits in a 32-bit integer.
    unsigned x_high = x >> 32, x_low = (unsigned)x, quot, rem;
    asm("divl %4\\n" : "=a"(quot), "=d"(rem) : "d"(x_high), "a"(x_low), "r"(m));
    return rem;
  }

  modnum &operator+=(const modnum &o) {
    v += o.v;
    if (v >= MOD)
      v -= MOD;
    return *this;
  }
  modnum &operator-=(const modnum &o) {
    v -= o.v;
    if (v < 0)
      v += MOD;
    return *this;
  }
  modnum &operator*=(const modnum &o) {
    v = fast_mod(vv_t(v) * o.v);
    return *this;
  }
  modnum operator-() {
    modnum res;
    if (v)
      res.v = MOD - v;
    return res;
  }
  friend modnum operator+(const modnum &a, const modnum &b) {
    return modnum(a) += b;
  }
  friend modnum operator-(const modnum &a, const modnum &b) {
    return modnum(a) -= b;
  }
  friend modnum operator*(const modnum &a, const modnum &b) {
    return modnum(a) *= b;
  }

  modnum pow(vv_t e) const {
    if (e < 0)
      return 1 / this->pow(-e);
    if (e == 0)
      return 1;
    if (e & 1)
      return *this * this->pow(e - 1);
    return (*this * *this).pow(e / 2);
  }

  modnum inv() const {
    v_t g = MOD, x = 0, y = 1;
    for (v_t r = v; r != 0;) {
      v_t q = g / r;
      g %= r;
      swap(g, r);
      x -= q * y;
      swap(x, y);
    }

    assert(g == 1);
    assert(y == MOD || y == -MOD);
    return x < 0 ? x + MOD : x;
  }
  modnum &operator/=(const modnum &o) { return (*this) *= o.inv(); }
  friend modnum operator/(const modnum &a, const modnum &b) {
    return modnum(a) /= modnum(b);
  }

  static constexpr v_t totient() {
    v_t tot = MOD, tmp = MOD;
    for (v_t p = 2; p * p <= tmp; p++)
      if (tmp % p == 0) {
        tot = tot / p * (p - 1);
        while (tmp % p == 0)
          tmp /= p;
      }
    if (tmp > 1)
      tot = tot / tmp * (tmp - 1);
    return tot;
  }

  static v_t primitive_root() {
    if (MOD == 1)
      return 0;
    if (MOD == 2)
      return 1;

    v_t tot = totient(), tmp = tot;
    vi tot_pr;
    for (v_t p = 2; p * p <= tmp; p++)
      if (tot % p == 0) {
        tot_pr.push_back(p);
        while (tmp % p == 0)
          tmp /= p;
      }
    if (tmp > 1)
      tot_pr.push_back(tmp);

    for (v_t r = 2; r < MOD; r++)
      if (__gcd(r, MOD) == 1) {
        bool root = true;
        for (v_t p : tot_pr)
          root &= modnum(r).pow(tot / p) != 1;
        if (root)
          return r;
      }
    assert(false);
  }

  static modnum generator() {
    static modnum g = primitive_root();
    return g;
  }
  static v_t discrete_log(modnum v) {
    static const v_t M = ceil(sqrt(MOD));
    static unordered_map<v_t, v_t> table;
    if (table.empty()) {
      modnum e = 1;
      for (v_t i = 0; i < M; i++) {
        table[e.v] = i;
        e *= generator();
      }
    }
    static modnum f = generator().pow(totient() - M);

    for (v_t i = 0; i < M; i++) {
      if (table.count(v.v))
        return table[v.v] + i * M;
      v *= f;
    }
    assert(false);
  }

  static modnum unity_root(int deg) {
    assert(totient() % deg == 0);
    return generator().pow(totient() / deg);
  }

  static modnum unity_root(int deg, int pow) {
    static vector<modnum> table{0, 1};
    while (sz(table) <= deg) {
      modnum w = unity_root(sz(table));
      for (int i = sz(table) / 2, s = sz(table); i < s; i++) {
        table.push_back(table[i]);
        table.push_back(table[i] * w);
      }
    }
    return table[deg + (pow < 0 ? deg + pow : pow)];
  }

  static modnum factorial(int n) {
    static vector<modnum> fact = {1};
    assert(n >= 0);
    if (sz(fact) <= n) {
      int had = sz(fact);
      fact.resize(n + 1);
      for (int i = had; i <= n; i++)
        fact[i] = fact[i - 1] * i;
    }
    return fact[n];
  }
  static modnum inverse_factorial(int n) {
    static vector<modnum> finv = {1};
    assert(n >= 0);
    if (sz(finv) <= n) {
      int had = sz(finv);
      finv.resz(n + 1), finv[n] = factorial(n).inv();
      for (int i = n - 1; i >= had; i--)
        finv[i] = finv[i + 1] * (i + 1);
    }
    return finv[n];
  }

  static modnum small_inv(int n) {
    assert(n > 0);
    return factorial(n - 1) * inverse_factorial(n);
  }

  static modnum ncr(int n, int r) {
    if (r < 0 || n < r)
      return 0;
    return factorial(n) * inverse_factorial(r) * inverse_factorial(n - r);
  }
};
// }}}
using mn = modnum<int(998244353)>;
using vmn = vector<mn>;
using vvmn = vector<vmn>;

int main() {
  setIO();

  string s;
  re(s);
  int K;
  re(K);

  map<pii, mn> dp, DP;

  reverse(all(s));

  int i = 0;
  while (i < sz(s) && s[i] == '1')
    i++;

  F0R(take, i + 1) { dp[{take, take}] = 1; }

  for (int j = i; i < sz(s); i = j) {
    assert(s[i] == '0');
    j = i + 1;
    while (j < sz(s) && s[j] == '1')
      j++;

    int exist = j - i - 1;

    DP.clear();
    trav(e, dp) {
      auto [have, moves] = e.f;
      F0R(leave, exist + have + 1) {
        DP[{exist + have - leave, moves + max(0, exist - leave)}] += e.s;
      }
    }
    swap(dp, DP);
  }

  mn ans = 0;
  trav(e, dp) {
    if (e.f.f == 0 && e.f.s <= K)
      ans += e.s;
  }
  ps(ans);

  // did you check N=1? did you mix up N,M?
  // check your "infinity" and "null" values against the bounds
  return 0;
}