Problem p00451 (C++) — buggy submission, verdict: Memory Limit Exceeded

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <set>
#include <string>
#include <vector>

template <intmax_t X = 943681729, intmax_t MOD = 1000000007>
class rolling_hash {
  std::vector<intmax_t> hash, offset;

public:
  rolling_hash(const std::string &s)
      : hash(s.length() + 1), offset(s.length() + 1) {
    for (size_t i = 0; i < s.length(); ++i)
      hash[i + 1] = (hash[i] * X + s[i]) % MOD;

    offset[0] = 1;
    for (size_t i = 1; i <= s.length(); ++i)
      offset[i] = offset[i - 1] * X % MOD;
  }

  intmax_t get_base() const { return X; }
  intmax_t get_mod() const { return MOD; }

  intmax_t prefix(size_t i) const {
    // hash of prefix s[0..i-1] (inclusive)
    assert(0 < i);
    return hash[i];
  }

  intmax_t substr(size_t i, size_t j) const {
    // hash of substring s[i..j-1] (inclusive)
    assert(i < j);
    intmax_t res = hash[j];
    res = (res - offset[j - i] * hash[i]) % MOD;
    if (res < 0)
      res += MOD;
    return res;
  }

  intmax_t inserted(size_t i, int ch) const {
    intmax_t res = 0;
    if (i > 0)
      res += prefix(i);
    res = (res * X + ch) % MOD;
    size_t n = hash.size() - 1;
    if (i < n)
      res = (res * offset[n - i] + substr(i, n)) % MOD;
    return res;
  }

  void debug() const {
    for (size_t i = 0; i < hash.size(); ++i)
      fprintf(stderr, "%jd%c", hash[i], i + 1 < hash.size() ? ' ' : '\\n');
  }
};

int testcase_ends() {
  char buf[4096];
  if (scanf("%s", buf) == EOF)
    return 1;
  std::string s = buf;
  scanf("%s", buf);
  std::string t = buf;

  if (s.length() > t.length())
    std::swap(s, t);

  size_t n = s.length();
  size_t m = t.length();

  rolling_hash<> rs(s), rt(t);

  size_t lb = 0;
  size_t ub = n + 1;
  while (ub - lb > 1) {
    size_t w = (lb + ub) >> 1;
    std::set<intmax_t> rl;
    bool found = false;
    for (size_t i = 0; i + w <= n; ++i)
      rl.insert(rs.substr(i, i + w));

    for (size_t i = 0; i + w <= m; ++i)
      if (rl.count(rt.substr(i, i + w))) {
        found = true;
        break;
      }

    (found ? lb : ub) = w;
  }

  printf("%zu\\n", lb);
  return 0;
}

int main() {
  while (!testcase_ends()) {
  }
}


Error: MLE

Fixed submission:

#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>

template <class String> class matching_automaton {
  using char_type = typename String::value_type;
  struct node {
    size_t length = 0;
    std::shared_ptr<node> output_link = nullptr;
    std::shared_ptr<node> suffix_link = nullptr;
    std::map<char_type, std::shared_ptr<node>> links;
    bool accepting = false;

    std::shared_ptr<node> append(char_type c) {
      auto it = links.lower_bound(c);
      if (it != links.end() && it->first == c)
        return it->second;
      std::shared_ptr<node> newnode(new node);
      newnode->length = length + 1;
      links.emplace_hint(it, c, newnode);
      return newnode;
    }

    std::shared_ptr<node> find(char_type c) const {
      auto it = links.find(c);
      return (it != links.end()) ? it->second : nullptr;
    }
  };
  std::shared_ptr<node> root;

  template <class ForwardIt> void build_nodes(ForwardIt first, ForwardIt last) {
    for (auto it = first; it != last; ++it) {
      std::shared_ptr<node> cur = root;
      for (char_type c : *it)
        cur = cur->append(c);
      cur->accepting = true;
    }
  }

  void build_links() {
    std::queue<std::shared_ptr<node>> q;
    for (const auto &p : root->links) {
      q.emplace(p.second);
      p.second->suffix_link = root;
    }

    while (!q.empty()) {
      std::shared_ptr<node> cur(q.front());
      q.pop();
      std::set<char_type> cc;
      for (const auto &p : cur->links) {
        cc.insert(p.first);
        p.second->suffix_link = root;
        q.emplace(p.second);
      }
      for (auto sf = cur->suffix_link; sf; sf = sf->suffix_link) {
        for (auto it = cc.begin(); it != cc.end();) {
          char_type c = *it;
          std::shared_ptr<node> dst(sf->find(c));
          if (!dst) {
            ++it;
            continue;
          }
          cur->find(c)->suffix_link = dst;
          it = cc.erase(it);
        }
        if (cc.empty())
          break;
      }

      if (cur->suffix_link->accepting) {
        cur->output_link = cur->suffix_link;
      } else if (cur->suffix_link->output_link) {
        cur->output_link = cur->suffix_link->output_link;
      }
    }
  }

  template <class Functor> void match_do(const String &s, Functor fn) const {
    std::shared_ptr<node> cur(root);
    for (size_t i = 0; i < s.length(); ++i) {
      char_type c = s[i];
      std::shared_ptr<node> next(cur->find(c));
      if (next) {
        cur = next;
      } else {
        while (cur != root && !cur->find(c))
          cur = cur->suffix_link;
        if (cur->find(c))
          cur = cur->find(c);
      }
      if (cur->accepting)
        fn(i + 1 - cur->length, cur->length);
      std::shared_ptr<node> out(cur->output_link);
      while (out) {
        fn(i + 1 - out->length, out->length);
        out = out->output_link;
      }
    }
  }

public:
  template <class ForwardIt>
  matching_automaton(ForwardIt first, ForwardIt last) : root(new node) {
    build_nodes(first, last);
    build_links();
  }

  std::vector<size_t> longest_matches(const String &s) {
    std::vector<size_t> res(s.length());
    match_do(s, [&](size_t i, size_t j) { res[i] = std::max(res[i], j); });
    return res;
  }

  size_t longest_match(const String &s) {
    size_t res = 0;
    match_do(s, [&](size_t i, size_t j) { res = std::max(res, j); });
    return res;
  }
};

int testcase_ends() {
  char buf[4096];
  if (scanf("%s", buf) == EOF)
    return 1;
  std::string s = buf;
  scanf("%s", buf);
  std::string t = buf;

  if (s.length() > t.length())
    std::swap(s, t);

  size_t n = s.length();
  size_t m = t.length();

  std::vector<std::string> ps;
  for (size_t i = 0; i < n; ++i)
    for (size_t j = 0; i + j <= n; ++j)
      ps.push_back(s.substr(i, j));

  matching_automaton<std::string> pma(ps.begin(), ps.end());
  printf("%zu\\n", pma.longest_match(t));

  return 0;
}

int main() {
  while (!testcase_ends()) {
  }
}