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

#include <cassert>
#include <iostream>
#include <set>
#include <vector>
using namespace std;
#define repeat(i, n) for (int i = 0; i < (n); ++i)

typedef unsigned long long hash_t;
static const hash_t base = 1e9 + 7; // mod is 2^64 (overflow)

int main() {
  ios_base::sync_with_stdio(false);
  int n, m;
  cin >> n >> m;
  string s;
  cin >> s;
  set<hash_t> ans;
  vector<hash_t> pow(s.length() + 1);
  pow[0] = 1;
  vector<hash_t> hash(s.length() + 1);
  hash[0] = 0;
  repeat(i, (int)s.length()) {
    pow[i + 1] = pow[i] * base;
    hash[i + 1] = hash[i] * base + s[i];
  }
  int l = 0, r = 1; // [l,r)
  repeat(k, m) {
    string query;
    cin >> query;
    if (query == "L++")
      ++l;
    else if (query == "L--")
      --l;
    else if (query == "R++")
      ++r;
    else if (query == "R--")
      --r;
    else
      assert(false);
    hash_t h = hash[r] - hash[l] * pow[r - l];
    ans.insert(h);
  }
  cout << ans.size() << endl;
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <vector>
using namespace std;
#define repeat(i, n) for (int i = 0; i < (n); ++i)

#include <map>
#include <string>
#include <vector>
#ifdef DEBUG
#include <cassert>
#endif
#ifndef repeat
#define repeat(i, n) for (int i = 0; i < (n); ++i)
#endif

// rolling hash
// hash(str) = ( c_1*b^{m-1} + c_2*b^{m-2} + ... + c_m*b^0 ) mod h
//     where { c_1, c_2, ..., c_m } = str
// hash(str[k+1..k+m]) = (               c_{k+1}*b^{m-1} + c_2*b^{m-2} + ... +
// c_{k+m}*b^0 ) mod h hash(str[k..k+m-1]) = ( c_k*b^{m-1} + c_{k+1}*b^{m-2} +
// ... + c_{k+m-1}*b^0               ) mod h hash(str[k+1..k+m]) = (
// hash(str[k..k+m-1])*b - str[k]*b^m + str[k+m] ) mod h

namespace rabin_karp {
using namespace std;
typedef unsigned long long hash_t;
// static const hash_t base = 1e9+7; // mod is 2^64 (overflow)
static const hash_t base = 1e2; // mod is 2^64 (overflow)

static map<int, hash_t> memo;
hash_t base_to(int n) {
  const map<int, hash_t>::iterator it = memo.find(n);
  if (it != memo.end())
    return it->second;
  hash_t x;
  if (n == 0) {
    x = 1;
  } else {
    x = base_to(n >> 1);
    x *= x;
    if (n & 1)
      x *= base;
  }
  memo.insert(make_pair(n, x));
  return x;
}

hash_t rolling_hash() { return 0; }
hash_t rolling_hash(const string &s) {
  hash_t a = 0;
  repeat(i, (int)s.length()) a = a * base + s[i];
  return a;
}

hash_t roll(hash_t a, char out, char in, hash_t base_to_len) {
  return a * base - out * base_to_len + in;
}
hash_t roll(hash_t a, char out, char in, int n) {
  return roll(a, out, in, base_to(n));
}
// hash_t push_back (hash_t a, char c, int n) { return roll(a,  0, c, n); }
// hash_t pop_back  (hash_t a, char c, int n) { return roll(a,  0,-c, n); }
// hash_t push_front(hash_t a, char c, int n) { return roll(a,  c, 0, n); }
// hash_t pop_front (hash_t a, char c, int n) { return roll(a, 0, -c, n); }

// find sub-string `b' of `a', and return the index or `-1' as not found
int find(const string &a, const string &b) {
  const int al = a.length();
  const int bl = b.length();
  const hash_t bh = rolling_hash(b);
  hash_t ah = rolling_hash(a.substr(0, bl));
  const hash_t base_to_len = base_to(bl);
  repeat(i, al - (bl - 1)) {
    if (ah == bh and a.substr(i, bl) == b)
      return i;        // equal on hash -> verify
    if (i + bl < al) { // there is next loop
      ah = roll(ah, a[i], a[i + bl], base_to_len);
    }
  }
  return -1;
}

// returns the index of `a' and the index of the sub-string in `bs', of -1 * -1.
// required: the length of strings in `bs' are all the same.
pair<int, int> find_set(const string &a, const vector<string> &bs) {
  const int al = a.length();
  const int bn = bs.size();
  if (bs.size() == 0)
    return make_pair(-1, -1);
  const int bl = bs[0].length();
#ifdef DEBUG
  repeat(i, bn) assert(bl == (int)bs[i].length());
#endif
  vector<hash_t> bhs(bn);
  repeat(i, bn) bhs[i] = rolling_hash(bs[i]);
  hash_t ah = rolling_hash(a.substr(0, bl));
  const hash_t base_to_len = base_to(bl);
  repeat(i, al - (bl - 1)) {
    repeat(j, bn) {
      if (ah == bhs[j] and a.substr(i, bl) == bs[j])
        return make_pair(i, j);
    }
    if (i + bl < al) {
      ah = roll(ah, a[i], a[i + bl], base_to_len);
    }
  }
  return make_pair(-1, -1);
}

vector<int> find_all(const string &a, const string &b) {
  const int al = a.length();
  const int bl = b.length();
  const hash_t bh = rolling_hash(b);
  hash_t ah = rolling_hash(a.substr(0, bl));
  const hash_t base_to_len = base_to(bl);
  vector<int> result;
  repeat(i, al - (bl - 1)) {
    if (ah == bh and a.substr(i, bl) == b)
      result.push_back(i);
    if (i + al < bl) { // there is next loop
      ah = roll(ah, a[i], a[i + al], base_to_len);
    }
  }
  return result;
}
} // namespace rabin_karp
typedef rabin_karp::hash_t hash_t;

int main() {
  int n, m;
  cin >> n >> m;
  string s;
  cin >> s;
  int l = 0, r = 1; // [l,r)
  hash_t h = rabin_karp::rolling_hash(s.substr(l, r - l));
  vector<hash_t> hs;
  repeat(k, m) {
    string query;
    cin >> query;
    if (query == "L++") {
      // h = rabin_karp::pop_front(h, s[l], r-l);
      ++l;
    } else if (query == "L--") {
      --l;
      // h = rabin_karp::push_front(h, s[l], r-l);
    } else if (query == "R++") {
      ++r;
      // h = rabin_karp::push_back(h, s[r-1], r-l);
    } else if (query == "R--") {
      // h = rabin_karp::pop_back(h, s[r-1], r-l);
      --r;
    } else {
      assert(false);
    }
    h = rabin_karp::rolling_hash(s.substr(l, r - l));
    if (find(hs.begin(), hs.end(), h) == hs.end()) {
      hs.push_back(h);
    }
  }
  cout << hs.size() << endl;
  return 0;
}