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

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct SuffixArray {
  const string s;
  vector<int> SuffixArr;
  vector<int> lcp;

  SuffixArray(const string str) : s(str) {
    construct_suffix_array();
    construct_lcp();
  }

  // Suffix Array の構築
  void construct_suffix_array() {
    const int len = s.length();
    vector<int> tmp(len, 0);
    vector<int> rank(len, 0);
    int k;

    SuffixArr.resize(len);
    rank.resize(len);

    for (int i = 0; i < len; ++i) {
      SuffixArr[i] = i;
      rank[i] = s[i];
    }

    // ソート比較用関数 ([&] は変数の参照キャプチャ)
    auto compare_sa = [&](int i, int j) {
      if (rank[i] != rank[j]) {
        return rank[i] < rank[j];
      }
      int ri = (i + k < len) ? rank[i + k] : -1;
      int rj = (j + k < len) ? rank[j + k] : -1;
      return ri < rj;
    };

    for (k = 1; k <= len; k *= 2) {
      sort(SuffixArr.begin(), SuffixArr.end(), compare_sa);
      tmp[SuffixArr[0]] = 0;
      for (int i = 1; i < len; ++i) {
        int c = compare_sa(SuffixArr[i - 1], SuffixArr[i]) ? 1 : 0;
        tmp[SuffixArr[i]] = tmp[SuffixArr[i - 1]] + c;
      }
      for (int i = 0; i < len; ++i) {
        rank[i] = tmp[i];
      }
    }
  }

  // 高さ配列の構築
  void construct_lcp() {
    int l = s.length();
    vector<int> rank(l);
    lcp.resize(l);
    for (int i = 0; i < l; ++i) {
      rank[SuffixArr[i]] = i;
      lcp[i] = 0;
    }
    for (int i = 0, h = 0; i < l; i++) {
      if (rank[i] + 1 < l) {
        for (int j = SuffixArr[rank[i] + 1];
             max(i, j) + h < SuffixArr.size() && s[i + h] == s[j + h]; ++h)
          ;
        lcp[rank[i] + 1] = h;
        if (h > 0) {
          --h;
        }
      }
    }
    return;
  }

  // S の s_idx 文字目からの文字列と, P の p_idx 文字目からの文字列の比較
  bool substr_less_than(const string &p, int s_idx = 0, int p_idx = 0) {
    int len_s = s.length();
    int len_p = p.length();
    while (s_idx < len_s && p_idx < len_p) {
      if (s[s_idx] < p[p_idx]) {
        return true;
      } else if (s[s_idx] > p[p_idx]) {
        return false;
      }
      s_idx++;
      p_idx++;
    }
    return (s_idx >= len_s) && (p_idx < len_p);
  }

  pair<int, int> lower_upper_bound(string p) {
    int lb, ub;
    auto binary_search = [&](int lo, int hi) {
      while (hi - lo > 1) {
        int mid = (hi + lo) / 2;
        if (substr_less_than(p, SuffixArr[mid])) {
          lo = mid;
        } else {
          hi = mid;
        }
      }
      return hi;
    };
    // lower_bound
    lb = binary_search(-1, s.length());
    // upper_bound
    p.back()++;
    ub = binary_search(lb - 1, s.length());
    return make_pair(lb, ub);
  }

  void show_output() {
    for (int i = 0; i < s.length(); ++i) {
      cout << i << " : lcp -> " << lcp[i] << ", suffix -> "
           << s.substr(SuffixArr[i]) << endl;
    }
  }
};

struct RollingHash {
  typedef long long lint;
  const string str;
  const lint base, mod;
  vector<lint> hash, pw;

  RollingHash(const string &s, lint h = 1000000007, lint b = 1009)
      : str(s), mod(h), base(b) {
    int l = s.length();
    hash.assign(l + 1, 0);
    pw.assign(l + 1, 0);
    pw[0] = 1;
    for (int i = 0; i < l; ++i) {
      pw[i + 1] = pw[i] * base % mod;
      hash[i + 1] = (hash[i] * base + s[i]) % mod;
    }
  }

  lint const get_hash(int l, int r) {
    return ((hash[r] - hash[l] * pw[r - l]) % mod + mod) % mod;
  }
};

int main(void) {
  string S;
  cin >> S;
  int N;
  cin >> N;
  // vector<string> P(N);
  SuffixArray SA(S);
  for (int i = 0; i < N; i++) {
    // cin >> P.at(i);
    // int n = P.size();
    string P;
    cin >> P;
    auto p = SA.lower_upper_bound(P);
    if (p.first == p.second) {
      cout << 0 << endl;
    } else {
      cout << 1 << endl;
    }
  }
  return 0;
}


Error: MLE

Fixed submission:

// This file is a "Hello, world!" in C++ language by GCC for wandbox.
#include "bits/stdc++.h"

using namespace std;

typedef unsigned long long ull;

struct RollingHash {
  vector<ull> hash, pow;
  RollingHash(string s, ull _b = 1000000007) {
    _b = _b;
    int sz = s.length();
    hash.assign(sz + 1, 0);
    pow.assign(sz + 1, 0);

    pow[0] = 1;
    for (int i = 0; i < sz; i++) {
      pow[i + 1] = pow[i] * _b;
    }
    for (int i = 0; i < sz; i++) {
      hash[i + 1] = (hash[i] + s[i]) * _b;
    }
  }
  // s[l]s[l+1]....s[r-1]縺ョ繝上ャ繧キ繝・蛟、繧貞叙蠕励☆繧?
  // 蜊企幕蛹コ髢?
  ull get(int l, int r) { return (hash[r] - hash[l] * pow[r - l]); }
};
#define rep(i, n) for (int i = 0; i < n; i++)
int main() {
  string t;
  cin >> t;
  int q;
  cin >> q;
  RollingHash hash(t);
  unordered_set<ull> s;
  rep(i, t.size()) {
    rep(j, min(1000, (int)t.size() - i)) { s.insert(hash.get(i, i + j + 1)); }
  }
  rep(i, q) {
    string p;
    cin >> p;
    cout << s.count(RollingHash(p).get(0, p.size())) << endl;
  }
}

// GCC reference:
//   https://gcc.gnu.org/

// C++ language references:
//   https://msdn.microsoft.com/library/3bstk3k5.aspx
//   http://www.cplusplus.com/
//   https://isocpp.org/
//   http://www.open-std.org/jtc1/sc22/wg21/

// Boost libraries references:
//   http://www.boost.org/doc/