Problem p02913 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using ll = long long;

struct RollingHash {
  ll base1 = 1009;
  ll base2 = 2009;
  ll mod1 = 1000000007;
  ll mod2 = 1000000009;
  vector<ll> hash1, hash2, pow1, pow2;

  RollingHash(const string &S) {
    int n = (int)S.size();
    hash1.assign(n + 1, 0);
    hash2.assign(n + 1, 0);
    pow1.assign(n + 1, 1);
    pow2.assign(n + 1, 1);
    for (int i = 0; i < n; ++i) {
      hash1[i + 1] = (hash1[i] * base1 + S[i]) % mod1;
      hash2[i + 1] = (hash2[i] * base2 + S[i]) % mod2;
      pow1[i + 1] = (pow1[i] * base1) % mod1;
      pow2[i + 1] = (pow2[i] * base2) % mod2;
    }
  }

  inline pair<ll, ll> get(int l, int r) const {
    ll res1 = hash1[r] - hash1[l] * pow1[r - l] % mod1;
    if (res1 < 0)
      res1 += mod1;
    ll res2 = hash2[r] - hash2[l] * pow2[r - l] % mod2;
    if (res2 < 0)
      res2 += mod2;
    return {res1, res2};
  }

  inline int getLCP(int a, int b) const {
    int len = min((int)hash1.size() - a, (int)hash1.size() - b);
    int low = 0, high = len;
    while (high - low > 1) {
      int mid = (low + high) >> 1;
      if (get(a, a + mid) != get(b, b + mid))
        high = mid;
      else
        low = mid;
    }
    return low;
  }
};

int main() {
  int N;
  string S;
  cin >> N >> S;
  RollingHash rollingHash(S);

  int res = 0;
  for (int i = 0; i < N; ++i) {
    for (int j = i + 1; j < N; ++j) {
      int lcp = rollingHash.getLCP(i, j);
      lcp = min(lcp, j - i);
      res = max(res, lcp);
    }
  }

  cout << res << endl;
}


Fixed submission:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using ll = long long;

struct RollingHash {
  static const ll base1 = 1009;
  static const ll base2 = 2009;
  static const ll mod1 = 1000000007;
  static const ll mod2 = 1000000009;
  vector<ll> hash1, hash2, pow1, pow2;

  RollingHash(const string &S) {
    int n = (int)S.size();
    hash1.assign(n + 1, 0);
    hash2.assign(n + 1, 0);
    pow1.assign(n + 1, 1);
    pow2.assign(n + 1, 1);
    for (int i = 0; i < n; ++i) {
      hash1[i + 1] = (hash1[i] * base1 + S[i]) % mod1;
      hash2[i + 1] = (hash2[i] * base2 + S[i]) % mod2;
      pow1[i + 1] = (pow1[i] * base1) % mod1;
      pow2[i + 1] = (pow2[i] * base2) % mod2;
    }
  }

  inline pair<ll, ll> get(int l, int r) const {
    ll res1 = hash1[r] - hash1[l] * pow1[r - l] % mod1;
    if (res1 < 0)
      res1 += mod1;
    ll res2 = hash2[r] - hash2[l] * pow2[r - l] % mod2;
    if (res2 < 0)
      res2 += mod2;
    return {res1, res2};
  }

  inline int getLCP(int a, int b) const {
    int len = min((int)hash1.size() - a, (int)hash1.size() - b);
    int low = 0, high = len;
    while (high - low > 1) {
      int mid = (low + high) >> 1;
      if (get(a, a + mid) != get(b, b + mid))
        high = mid;
      else
        low = mid;
    }
    return low;
  }
};

int main() {
  int N;
  string S;
  cin >> N >> S;
  RollingHash rollingHash(S);

  int res = 0;
  for (int i = 0; i < N; ++i) {
    for (int j = i + 1; j < N; ++j) {
      int lcp = rollingHash.getLCP(i, j);
      lcp = min(lcp, j - i);
      res = max(res, lcp);
    }
  }

  cout << res << endl;
}