Problem p02589 (C++)

Buggy submission (status: Runtime Error):
#ifdef DBG1
#define _GLIBCXX_DEBUG
#endif

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>

#ifdef DBG1
#define dbg(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define dbg(...)
#endif

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;

const int P = 200003;

int sum(int a, int b) {
  if ((a += b) >= P) {
    a -= P;
  }
  return a;
}

int diff(int a, int b) {
  if ((a -= b) < 0) {
    a += P;
  }
  return a;
}

int prod(int a, int b) { return int(ll(a) * b % P); }

int power(int a, int n) {
  int b = 1;
  while (n) {
    if (n & 1) {
      b = prod(a, b);
    }
    a = prod(a, a);
    n /= 2;
  }
  return b;
}

int inv(int a) { return power(a, P - 2); }

int quotient(int a, int b) { return prod(a, inv(b)); }

int &add(int &a, int b) { return a = sum(a, b); }

int &subtract(int &a, int b) { return a = diff(a, b); }

int &mult(int &a, int b) { return a = prod(a, b); }

int &div(int &a, int b) { return a = quotient(a, b); }

ll gcd(ll a, ll b) {
  if (b == 0) {
    return a;
  } else {
    return gcd(b, a % b);
  }
}

bool solve() {
  int n;
  if (scanf("%d", &n) != 1) {
    return false;
  }

  vector<string> w;
  for (int i = 0; i < n; ++i) {
    static char s[200100];
    scanf("%s", s);
    w.emplace_back(s);
  }

  auto calc_suffix_hash = [](const string &s, int len) -> ll {
    const int P1 = int(1e6) + 3;
    const int P2 = 997;
    const int MOD = int(1e9) + 7;
    ll hash1 = 0;
    ll hash2 = 0;
    assert(len < s.length());
    for (int i = 0; i < len; ++i) {
      hash1 = (hash1 * P1 + s[s.length() - i - 1]) % MOD;
      hash2 = (hash2 * P2 + s[s.length() - i - 1]) % MOD;
    }
    return (hash1 << 32) | hash2;
  };

  sort(w.begin(), w.end(), [](const auto &s1, const auto &s2) {
    return s1.length() < s2.length();
  });

  ll res = 0;

  vector<vector<int>> mask(n);
  for (int i = 0; i < n; ++i) {
    auto &s = w[i];
    auto &v = mask[i];
    v.resize(s.length());
    for (int j = 0; j < (int)s.length(); ++j) {
      if (j)
        v[j] = v[j - 1];
      v[j] |= (1 << (s[j] - 'a'));
    }
  }

  for (int i = 0; i < n;) {
    int j = i;
    while (j < n && w[i].length() == w[j].length()) {
      j++;
    }

    int len = (int)w[i].length();
    vector<pair<pair<ll, char>, int>> hashes;
    hashes.reserve(j - i);
    for (int k = i; k < j; ++k) {
      hashes.emplace_back(make_pair(calc_suffix_hash(w[k], len - 1), w[k][0]),
                          1);
    }
    sort(hashes.begin(), hashes.end());
    int size = 1;
    for (int k = 1; k < int(hashes.size()); ++k) {
      if (hashes[size - 1].first == hashes[k].first) {
        hashes[size - 1].second++;
      } else {
        hashes[size++] = hashes[k];
      }
    }
    hashes.resize(size);

    for (int k = j; k < n; ++k) {
      auto suffix_hash = calc_suffix_hash(w[k], len - 1);
      auto ptr = lower_bound(hashes.begin(), hashes.end(),
                             make_pair(make_pair(suffix_hash, 'a'), 0));
      while (ptr != hashes.end() && ptr->first.first == suffix_hash) {
        if (mask[k][w[k].length() - len] & (1 << (ptr->first.second - 'a'))) {
          res += ptr->second;
        }
        ++ptr;
      }
    }

    i = j;
  }

  printf("%lld\n", res);

  return true;
}

int main() {
  while (solve()) {
  }
  return 0;
}


Fixed submission:
#ifdef DBG1
#define _GLIBCXX_DEBUG
#endif

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>

#ifdef DBG1
#define dbg(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define dbg(...)
#endif

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;

const int P = 200003;

int sum(int a, int b) {
  if ((a += b) >= P) {
    a -= P;
  }
  return a;
}

int diff(int a, int b) {
  if ((a -= b) < 0) {
    a += P;
  }
  return a;
}

int prod(int a, int b) { return int(ll(a) * b % P); }

int power(int a, int n) {
  int b = 1;
  while (n) {
    if (n & 1) {
      b = prod(a, b);
    }
    a = prod(a, a);
    n /= 2;
  }
  return b;
}

int inv(int a) { return power(a, P - 2); }

int quotient(int a, int b) { return prod(a, inv(b)); }

int &add(int &a, int b) { return a = sum(a, b); }

int &subtract(int &a, int b) { return a = diff(a, b); }

int &mult(int &a, int b) { return a = prod(a, b); }

int &div(int &a, int b) { return a = quotient(a, b); }

ll gcd(ll a, ll b) {
  if (b == 0) {
    return a;
  } else {
    return gcd(b, a % b);
  }
}

bool solve() {
  int n;
  if (scanf("%d", &n) != 1) {
    return false;
  }

  vector<string> w;
  for (int i = 0; i < n; ++i) {
    static char s[1000100];
    scanf("%s", s);
    w.emplace_back(s);
  }

  auto calc_suffix_hash = [](const string &s, int len) -> ll {
    const int P1 = int(1e6) + 3;
    const int P2 = 997;
    const int MOD = int(1e9) + 7;
    ll hash1 = 0;
    ll hash2 = 0;
    assert(len < s.length());
    for (int i = 0; i < len; ++i) {
      hash1 = (hash1 * P1 + s[s.length() - i - 1]) % MOD;
      hash2 = (hash2 * P2 + s[s.length() - i - 1]) % MOD;
    }
    return (hash1 << 32) | hash2;
  };

  sort(w.begin(), w.end(), [](const auto &s1, const auto &s2) {
    return s1.length() < s2.length();
  });

  ll res = 0;

  vector<vector<int>> mask(n);
  for (int i = 0; i < n; ++i) {
    auto &s = w[i];
    auto &v = mask[i];
    v.resize(s.length());
    for (int j = 0; j < (int)s.length(); ++j) {
      if (j)
        v[j] = v[j - 1];
      v[j] |= (1 << (s[j] - 'a'));
    }
  }

  for (int i = 0; i < n;) {
    int j = i;
    while (j < n && w[i].length() == w[j].length()) {
      j++;
    }

    int len = (int)w[i].length();
    vector<pair<pair<ll, char>, int>> hashes;
    hashes.reserve(j - i);
    for (int k = i; k < j; ++k) {
      hashes.emplace_back(make_pair(calc_suffix_hash(w[k], len - 1), w[k][0]),
                          1);
    }
    sort(hashes.begin(), hashes.end());
    int size = 1;
    for (int k = 1; k < int(hashes.size()); ++k) {
      if (hashes[size - 1].first == hashes[k].first) {
        hashes[size - 1].second++;
      } else {
        hashes[size++] = hashes[k];
      }
    }
    hashes.resize(size);

    for (int k = j; k < n; ++k) {
      auto suffix_hash = calc_suffix_hash(w[k], len - 1);
      auto ptr = lower_bound(hashes.begin(), hashes.end(),
                             make_pair(make_pair(suffix_hash, 'a'), 0));
      while (ptr != hashes.end() && ptr->first.first == suffix_hash) {
        if (mask[k][w[k].length() - len] & (1 << (ptr->first.second - 'a'))) {
          res += ptr->second;
        }
        ++ptr;
      }
    }

    i = j;
  }

  printf("%lld\n", res);

  return true;
}

int main() {
  while (solve()) {
  }
  return 0;
}