Problem p00461 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <complex>
#include <cstdio>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;

// common
#define BR "\\n"

#define ALL(c) (c).begin(), (c).end()
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define EACH(it, o) for (auto it = (o).begin(); it != (o).end(); ++it)
#define IN(l, v, r) ((l) <= (v) && (v) < (r))

typedef vector<int> vi;
typedef pair<int, int> pii;
typedef vector<pair<int, int>> vpii;
typedef long long ll;
typedef vector<long long> vl;
typedef pair<long long, long long> pll;
typedef vector<pair<long long, long long>> vpll;
typedef vector<string> vs;
typedef long double ld;

// config
#define MODE_DEBUG
// #define INF 1<<30
// #define EPS 1e-8
// const ll MOD =100000007;

// debug
#ifdef MODE_DEBUG
#define DUMP(x) cerr << #x << " = " << (x) << endl
#define DEBUG(x)                                                               \\
  DUMP(x) << " (L" << __LINE__ << ")"                                          \\
          << " " << __FILE__ << endl
#define CHECK(exp, act)                                                        \\
  if (exp != act) {                                                            \\
    DUMP(exp);                                                                 \\
    DEBUG(act);                                                                \\
  }
#define STOP(e)                                                                \\
  CHECK(e, true);                                                              \\
  if (!(e))                                                                    \\
    exit(1);
#else
#define DUMP(x)
#define DEBUG(x)
#define CHECK(exp, act)
#define STOP(e)
#endif

template <class T> inline string toString(const vector<T> &x) {
  stringstream ss;
  REP(i, x.size()) {
    if (i != 0)
      ss << " ";
    ss << x[i];
  }
  return ss.str();
}
template <class T> inline string toString(const vector<vector<T>> &map) {
  stringstream ss;
  REP(i, map.size()) {
    if (i != 0)
      ss << BR;
    ss << toString(map[i]);
  }
  return ss.str();
}
template <class K, class V> string toString(map<K, V> &x) {
  string res;
  stringstream ss;
  for (auto &p : x)
    ss << p.first << ":" << p.second << " ";
  return ss.str();
}

template <typename T, typename V> inline T mod(T v, V MOD) {
  return (v % MOD + MOD) % MOD;
}

namespace SegmentTreeSpace {
const int INF = 1 << 28;

// RMQ
struct SegmentTree {
  vector<int> dat; // dat[i] .. i,i+1のLCP
  int n, size;
  SegmentTree(int _n) {
    n = pow2Fit(_n);
    size = 2 * n - 1;
    dat = vector<int>(size);
    fill(ALL(dat), INF);
  }
  SegmentTree() { SegmentTree(0); }

  int pow2Fit(int n) {
    int v = 1;
    while (v < n)
      v <<= 1;
    return v;
  }
  void update(int v, int a) {
    v += n - 1;
    dat[v] = a;
    while (v > 0) {
      int parent = v = (v - 1) / 2;
      int chl = parent * 2 + 1, chr = parent * 2 + 2;
      dat[parent] = min(dat[chl], dat[chr]);
    }
  }
  // 0<=a<=b<n
  int query(int a, int b) { return query(0, a, b, 0, n); }

private:
  //[a,...,b] =min(dat[a],...,dat[b-1])
  int query(int v, int a, int b, int l, int r) {
    if (r <= a || b <= l)
      return INF; // out range
    if (a <= l && r <= b)
      return dat[v];

    int vl = query(v * 2 + 1, a, b, l, (l + r) / 2);
    int vr = query(v * 2 + 2, a, b, (l + r) / 2, r);
    return min(vl, vr);
  }
};
} // namespace SegmentTreeSpace

/*
Suffix array O(n lg^2 n)
LCP table O(n)
*/
namespace SuffixArraySpace {

using namespace SegmentTreeSpace;
class SuffixArray {
public:
  // sa 辞書順i番目の接尾辞の開始位置 [s...)
  // pos 文字列[i...)の辞書順位置 s
  /// LCP …Longest Common Prefix
  vector<int> sa, pos;

  SegmentTree lcp;
  SuffixArray(string S) : S(S) {
    lcp = SegmentTree(S.size());
    N = S.size();
    sa = vector<int>(N);
    pos = vector<int>(N);
    rank = vector<int>(N);
    buildSA();
    buildLCP();
  };
  int N, k;

private:
  string S;
  vector<int> rank;

  // class SufCmp{
  // 	public:
  // 		const SuffixArray& suf;
  // 		SufCmp(const SuffixArray& suf):suf(suf){
  // 		}
  // 		bool operator()(const int i,const int j) const{
  // 			if (suf.pos[i] != suf.pos[j])return suf.pos[i] <
  // suf.pos[j]; 			int i2=i+suf.k,j2=j+suf.k; 			return (i2 < suf.N && j2< suf.N) ?
  // suf.pos[i2] < suf.pos[j2] : i2 > j2;
  // 		}
  // };

  // O(nlog^2(n))
  void buildSA() {
    auto sufCmp = [&, this](int i, int j) {
      if (pos[i] != pos[j])
        return pos[i] < pos[j];
      i += k;
      j += k;
      return (i < N && j < N) ? pos[i] < pos[j] : i > j;
    };
    REP(i, N) sa[i] = i, pos[i] = S[i];
    for (k = 1;; k *= 2) {
      sort(ALL(sa), sufCmp);
      REP(i, N - 1) rank[i + 1] = rank[i] + sufCmp(sa[i], sa[i + 1]);
      REP(i, N) pos[sa[i]] = rank[i];
      if (rank[N - 1] == N - 1)
        break;
    }
  }
  // O(n)
  void buildLCP() {
    for (int i = 0, k = 0; i < N; ++i)
      if (pos[i] != N - 1) {
        for (int j = sa[pos[i] + 1]; S[i + k] == S[j + k];)
          ++k;
        lcp.update(pos[i], k);
        if (k)
          --k;
      }
  }

public:
  // libs
  // LCP[a,...b]を求める． Zを含む
  // O(log(n))
  int LCP(int a, int b) {
    if (a == b)
      return N - sa[a];
    return lcp.query(a, b);
  }

  // k-ミスマッチマッチング
  // O(k*n)
  static int mis_match_contains(const string &S, const string &T, int k) {
    string st = S + "#" + T;
    SuffixArray suf(st);
    int res = 0;
    for (int i = 0; i + (int)T.size() <= (int)S.size(); i++) {
      DUMP(i);
      int si = i, ti = S.size() + 1;
      DUMP(si);
      DUMP(ti);
      int match = 0;
      for (int j = 0; j <= k; j++) {
        if (!(si < (int)S.size() && ti < (int)st.size()))
          break;
        int l = suf.pos[si], r = suf.pos[ti];
        if (l > r)
          swap(l, r);
        int lcp = suf.LCP(l, r);
        match += lcp;
        si += lcp + 1;
        ti += lcp + 1;
      }
      DUMP(match);
      if (match == (int)T.size() - k)
        res++;
      DUMP(si);
      DUMP(ti);
      DUMP(res);
    }
    return res;
  }
  //: TODO 最長回文
};
} // namespace SuffixArraySpace

using namespace SuffixArraySpace;

int main() {
  while (true) {
    int n;
    cin >> n;
    if (n == 0)
      break;
    int m;
    cin >> m;
    string s;
    cin >> s;

    string ioi = "I";
    REP(i, n) ioi += "OI";
    // DUMP(ioi.size());
    SuffixArray suf(ioi + "#" + s);
    int res = 0;
    REP(i, suf.N) {}
    for (int i = ioi.size() + 1; i < suf.N; i++) {
      if (suf.LCP(suf.pos[0], suf.pos[i]) == ioi.size())
        res++;
    }
    cout << res << endl;
  }
  return 0;
}

Error: 0
ioi.size() = 3
ioi.size() = 5


Fixed submission:

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <complex>
#include <cstdio>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;

// common
#define BR "\\n"

#define ALL(c) (c).begin(), (c).end()
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define EACH(it, o) for (auto it = (o).begin(); it != (o).end(); ++it)
#define IN(l, v, r) ((l) <= (v) && (v) < (r))

typedef vector<int> vi;
typedef pair<int, int> pii;
typedef vector<pair<int, int>> vpii;
typedef long long ll;
typedef vector<long long> vl;
typedef pair<long long, long long> pll;
typedef vector<pair<long long, long long>> vpll;
typedef vector<string> vs;
typedef long double ld;

// config
#define MODE_DEBUG
// #define INF 1<<30
// #define EPS 1e-8
// const ll MOD =100000007;

// debug
#ifdef MODE_DEBUG
#define DUMP(x) cerr << #x << " = " << (x) << endl
#define DEBUG(x)                                                               \\
  DUMP(x) << " (L" << __LINE__ << ")"                                          \\
          << " " << __FILE__ << endl
#define CHECK(exp, act)                                                        \\
  if (exp != act) {                                                            \\
    DUMP(exp);                                                                 \\
    DEBUG(act);                                                                \\
  }
#define STOP(e)                                                                \\
  CHECK(e, true);                                                              \\
  if (!(e))                                                                    \\
    exit(1);
#else
#define DUMP(x)
#define DEBUG(x)
#define CHECK(exp, act)
#define STOP(e)
#endif

template <class T> inline string toString(const vector<T> &x) {
  stringstream ss;
  REP(i, x.size()) {
    if (i != 0)
      ss << " ";
    ss << x[i];
  }
  return ss.str();
}
template <class T> inline string toString(const vector<vector<T>> &map) {
  stringstream ss;
  REP(i, map.size()) {
    if (i != 0)
      ss << BR;
    ss << toString(map[i]);
  }
  return ss.str();
}
template <class K, class V> string toString(map<K, V> &x) {
  string res;
  stringstream ss;
  for (auto &p : x)
    ss << p.first << ":" << p.second << " ";
  return ss.str();
}

template <typename T, typename V> inline T mod(T v, V MOD) {
  return (v % MOD + MOD) % MOD;
}

namespace SegmentTreeSpace {
const int INF = 1 << 28;

// RMQ
struct SegmentTree {
  vector<int> dat; // dat[i] .. i,i+1のLCP
  int n, size;
  SegmentTree(int _n) {
    n = pow2Fit(_n);
    size = 2 * n - 1;
    dat = vector<int>(size);
    fill(ALL(dat), INF);
  }
  SegmentTree() { SegmentTree(0); }

  int pow2Fit(int n) {
    int v = 1;
    while (v < n)
      v <<= 1;
    return v;
  }
  void update(int v, int a) {
    v += n - 1;
    dat[v] = a;
    while (v > 0) {
      int parent = v = (v - 1) / 2;
      int chl = parent * 2 + 1, chr = parent * 2 + 2;
      dat[parent] = min(dat[chl], dat[chr]);
    }
  }
  // 0<=a<=b<n
  int query(int a, int b) { return query(0, a, b, 0, n); }

private:
  //[a,...,b] =min(dat[a],...,dat[b-1])
  int query(int v, int a, int b, int l, int r) {
    if (r <= a || b <= l)
      return INF; // out range
    if (a <= l && r <= b)
      return dat[v];

    int vl = query(v * 2 + 1, a, b, l, (l + r) / 2);
    int vr = query(v * 2 + 2, a, b, (l + r) / 2, r);
    return min(vl, vr);
  }
};
} // namespace SegmentTreeSpace

/*
Suffix array O(n lg^2 n)
LCP table O(n)
*/
namespace SuffixArraySpace {

using namespace SegmentTreeSpace;
class SuffixArray {
public:
  // sa 辞書順i番目の接尾辞の開始位置 [s...)
  // pos 文字列[i...)の辞書順位置 s
  /// LCP …Longest Common Prefix
  vector<int> sa, pos;

  SegmentTree lcp;
  SuffixArray(string S) : S(S) {
    lcp = SegmentTree(S.size());
    N = S.size();
    sa = vector<int>(N);
    pos = vector<int>(N);
    rank = vector<int>(N);
    buildSA();
    buildLCP();
  };
  int N, k;

private:
  string S;
  vector<int> rank;

  // class SufCmp{
  // 	public:
  // 		const SuffixArray& suf;
  // 		SufCmp(const SuffixArray& suf):suf(suf){
  // 		}
  // 		bool operator()(const int i,const int j) const{
  // 			if (suf.pos[i] != suf.pos[j])return suf.pos[i] <
  // suf.pos[j]; 			int i2=i+suf.k,j2=j+suf.k; 			return (i2 < suf.N && j2< suf.N) ?
  // suf.pos[i2] < suf.pos[j2] : i2 > j2;
  // 		}
  // };

  // O(nlog^2(n))
  void buildSA() {
    auto sufCmp = [&, this](int i, int j) {
      if (pos[i] != pos[j])
        return pos[i] < pos[j];
      i += k;
      j += k;
      return (i < N && j < N) ? pos[i] < pos[j] : i > j;
    };
    REP(i, N) sa[i] = i, pos[i] = S[i];
    for (k = 1;; k *= 2) {
      sort(ALL(sa), sufCmp);
      REP(i, N - 1) rank[i + 1] = rank[i] + sufCmp(sa[i], sa[i + 1]);
      REP(i, N) pos[sa[i]] = rank[i];
      if (rank[N - 1] == N - 1)
        break;
    }
  }
  // O(n)
  void buildLCP() {
    for (int i = 0, k = 0; i < N; ++i)
      if (pos[i] != N - 1) {
        for (int j = sa[pos[i] + 1]; S[i + k] == S[j + k];)
          ++k;
        lcp.update(pos[i], k);
        if (k)
          --k;
      }
  }

public:
  // libs
  // LCP[a,...b]を求める． Zを含む
  // O(log(n))
  int LCP(int a, int b) {
    if (a == b)
      return N - sa[a];
    return lcp.query(a, b);
  }

  // k-ミスマッチマッチング
  // O(k*n)
  static int mis_match_contains(const string &S, const string &T, int k) {
    string st = S + "#" + T;
    SuffixArray suf(st);
    int res = 0;
    for (int i = 0; i + (int)T.size() <= (int)S.size(); i++) {
      DUMP(i);
      int si = i, ti = S.size() + 1;
      DUMP(si);
      DUMP(ti);
      int match = 0;
      for (int j = 0; j <= k; j++) {
        if (!(si < (int)S.size() && ti < (int)st.size()))
          break;
        int l = suf.pos[si], r = suf.pos[ti];
        if (l > r)
          swap(l, r);
        int lcp = suf.LCP(l, r);
        match += lcp;
        si += lcp + 1;
        ti += lcp + 1;
      }
      DUMP(match);
      if (match == (int)T.size() - k)
        res++;
      DUMP(si);
      DUMP(ti);
      DUMP(res);
    }
    return res;
  }
  //: TODO 最長回文
};
} // namespace SuffixArraySpace

using namespace SuffixArraySpace;

int main() {
  while (true) {
    int n;
    cin >> n;
    if (n == 0)
      break;
    int m;
    cin >> m;
    string s;
    cin >> s;

    string ioi = "I";
    REP(i, n) ioi += "OI";
    DUMP(ioi.size());
    SuffixArray suf(ioi + "#" + s);
    int res = 0;
    REP(i, suf.N) {}
    for (int i = ioi.size() + 1; i < suf.N; i++) {
      if (suf.LCP(suf.pos[0], suf.pos[i]) == ioi.size())
        res++;
    }
    cout << res << endl;
  }
  return 0;
}