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

#include <cstdio>
#include <string>
#include <vector>

using namespace std;

const long long MOD = 1e9 + 7;
const long long BASE1 = 0x234567, BASE2 = 0x3456795;

long long modpow(long long b, long long e, long long p = MOD) {
  /* Exponentiation by squaring */
  // returns n == b**e (mod p)
  long long n = 1, a = b % p;
  while (e) {
    if (e & 1)
      (n *= a) %= p;

    (a *= a) %= p;
    e >>= 1;
  }
  return n;
}

long long modsub(long long a, long long b, long long p = MOD) {
  // returns n == a-b (mod p)
  return ((a - b) % p + p) % p;
}

int main() {
  size_t H, W;
  scanf("%zu %zu", &H, &W);
  vector<string> F(H);
  for (size_t i = 0; i < H; ++i) {
    char buf[1 << 10];
    scanf("%s", buf);
    F[i] = buf;
  }

  size_t R, C;
  scanf("%zu %zu", &R, &C);
  vector<string> G(R);
  for (size_t i = 0; i < R; ++i) {
    char buf[1 << 10];
    scanf("%s", buf);
    G[i] = buf;
  }

  long long target = 0;
  for (size_t i = 0; i < R; ++i) {
    long long key = 0;
    for (size_t j = 0; j < C; ++j)
      ((key *= BASE2) += G[i][j]) %= MOD;

    ((target *= BASE1) += key) %= MOD;
  }

  vector<vector<long long>> t1(H, vector<long long>(W));
  vector<vector<long long>> t2(H, vector<long long>(W));
  long long pow = modpow(BASE2, C, MOD);
  for (size_t i = 0; i < H; ++i) {
    long long key = 0;
    for (size_t j = 0; j < W; ++j) {
      ((key *= BASE2) += F[i][j]) %= MOD;
      if (j >= C)
        key = modsub(key, F[i][j - C] * pow, MOD);

      t1[i][j] = t2[i][j] = key;
    }
  }

  pow = modpow(BASE1, R, MOD);
  for (size_t i = 0; i < H; ++i)
    for (size_t j = 0; j < W; ++j) {
      if (i)
        (t1[i][j] += t1[i - 1][j] * BASE1) %= MOD;

      if (i >= R)
        t1[i][j] = modsub(t1[i][j], t2[i - R][j] * pow, MOD);

      if (t1[i][j] == target && i + 1 >= R && j + 1 >= C)
        printf("%zu %zu\\n", i - R + 1, j - C + 1);
    }

  return 0;
}

Error: TLE

Fixed submission:

#include <cstdio>
#include <string>
#include <vector>

using namespace std;

const long long MOD = 1e9 + 7;
const long long BASE = 0x234567;

struct RollingHash {
  string s;
  long long mod, base;
  vector<long long> hash, pow;
  RollingHash() {}
  RollingHash(string s, long long m, long long b) : s(s), mod(m), base(b) {
    pow.resize(s.length() + 1);
    pow[0] = 1;
    for (size_t i = 0; i < s.length(); ++i)
      (pow[i + 1] = pow[i] * base) %= mod;

    hash.assign(s.length() + 1, 0);
    for (size_t i = 0; i < s.length(); ++i)
      (hash[i + 1] = hash[i] + pow[i] * s[i]) %= mod;
  }
  long long get_hash(size_t first, size_t last) const {
    return (hash[last] - hash[first] + mod) % mod;
  }
  long long make_hash(string t) {
    long long h = 0;
    for (size_t i = 0; i < t.length(); ++i)
      (h += pow[i] * t[i]) %= mod;

    return h;
  }
  long long diff(long long h, size_t pos, size_t len) const {
    return (h * pow[pos] - get_hash(pos, pos + len) + mod) % mod;
  }
  bool is_equiv(long long h, size_t pos, size_t len) const {
    return !diff(h, pos, len);
  }
  template <class Functor> void findall(const string &t, Functor F) {
    long long h = make_hash(t);
    for (size_t pos = 0; pos + t.length() <= s.length(); ++pos)
      if (is_equiv(h, pos, t.length()))
        F(pos);
  }
};

bool is_equiv(const vector<RollingHash> &rhash,
              const vector<long long> &subhash, size_t pos1, size_t pos2,
              size_t r, size_t c) {
  for (size_t i = 0; i < r; ++i)
    if (!rhash[pos1 + i].is_equiv(subhash[i], pos2, c))
      return false;

  return true;
}

int main() {
  size_t H, W;
  scanf("%zu %zu", &H, &W);
  vector<string> F(H);
  for (size_t i = 0; i < H; ++i) {
    char buf[1 << 10];
    scanf("%s", buf);
    F[i] = buf;
  }

  size_t R, C;
  scanf("%zu %zu", &R, &C);
  vector<string> G(R);
  for (size_t i = 0; i < R; ++i) {
    char buf[1 << 10];
    scanf("%s", buf);
    G[i] = buf;
  }

  vector<RollingHash> rhash(H);
  for (size_t i = 0; i < H; ++i)
    rhash[i] = RollingHash(F[i], MOD, BASE);

  vector<long long> subhash(R);
  for (size_t i = 0; i < R; ++i)
    subhash[i] = rhash[0].make_hash(G[i]);

  for (size_t i = 0; i + R <= H; ++i)
    for (size_t j = 0; j + C <= W; ++j)
      if (is_equiv(rhash, subhash, i, j, R, C))
        printf("%zu %zu\\n", i, j);

  return 0;
}