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

#include <algorithm>
#include <bitset>
#include <climits>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>
using namespace std;

typedef long long ll;
typedef vector<int> VI;
typedef vector<ll> VL;

const double PI = 3.14159265358979323846;

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define REP1(i, n) for (int i = 1; i <= (int)(n); i++)
#define REPLL(i, n) for (ll i = 0; i < (ll)(n); i++)
#define REPLL1(i, n) for (ll i = 1; i <= (ll)(n); i++)
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)(x).size())
#define LEN(x) ((int)(x).length())
#define ZERO(a) memset(a, 0, sizeof(a))

#define RAD(d) (PI * (d) / 180)
#define DEG(r) (180.0 * (r) / PI)

template <class T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}

template <class T> void dump(const vector<T> &v) {
  REP(i, SZ(v) - 1) { cout << v[i] << " "; }
  cout << v[SZ(v) - 1] << endl;
}

template <class T> void dump(int w, int h, const vector<T> &v) {
  REP(j, h) {
    REP(i, w - 1) { cout << v[j * w + i] << " "; }
    cout << v[j * w + w - 1] << endl;
  }
}

template <class T> T accumulate(const vector<T> &v) {
  T sum = 0;
  REP(i, SZ(v)) { sum += v[i]; }
  return sum;
}

template <class T> T average(const vector<T> &v) {
  return accumulate(v) / SZ(v);
}

template <class T> struct Matrix {
  T w, h;
  vector<T> A;
  Matrix(T w_, T h_) : w(w_), h(h_), A(w * h) {}
  T get(T x, T y) const { return A[y * w + x]; }
};

template <class T> void input(Matrix<T> &m) {
  REP(j, m.h) {
    REP(i, m.w) { cin >> m.A[j * m.w + i]; }
  }
}

template <class T> Matrix<T> prod(const Matrix<T> &a, const Matrix<T> &b) {
  Matrix<T> m(b.w, a.h);

  REP(j, m.h) {
    REP(i, m.w) {
      ll c = 0;
      REP(k, a.w) { c += a.A[j * a.w + k] * b.A[k * b.w + i]; }
      m.A[j * m.w + i] = c;
    }
  }

  return m;
}

void dump(const Matrix<ll> &m) {
  REP(j, m.h) {
    REP(i, m.w - 1) { printf("%lld ", m.A[j * m.w + i]); }
    printf("%lld\\n", m.A[j * m.w + m.w - 1]);
  }
}

void dump(const Matrix<double> &m) {
  REP(j, m.h) {
    REP(i, m.w - 1) { printf("%f ", m.A[j * m.w + i]); }
    printf("%f\\n", m.A[j * m.w + m.w - 1]);
  }
}

string &to_upper(string &s) {
  REP(i, s.length()) {
    if ('a' <= s[i] && s[i] <= 'z') {
      s[i] -= 32;
    }
  }

  return s;
}

string &to_lower(string &s) {
  REP(i, s.length()) {
    if ('A' <= s[i] && s[i] <= 'Z') {
      s[i] += 32;
    }
  }

  return s;
}

// すべての約数を列挙する
template <class T> vector<T> get_divisors(T n) {
  vector<T> ret;
  for (T i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      ret.push_back(i);
      if (i * i != n)
        ret.push_back(n / i);
    }
  }
  sort(ALL(ret));
  return ret;
}

// 1-sqrt(N)までの約数を列挙する
template <class T> vector<T> get_divisors2(T n) {
  vector<T> ret;
  for (T i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      ret.push_back(i);
    }
  }
  return ret;
}

// modint 構造体を使ってみませんか？ (C++) - noshi91のメモ
// https://noshi91.hatenablog.com/entry/2019/03/31/174006
//
// 使い方:
//   const int MOD = 1000000007;
//   using mint = modint<MOD>;
//   mint a = 1234;
//
template <std::uint_fast64_t Modulus> class modint {
  using u64 = std::uint_fast64_t;

public:
  u64 a;

  constexpr modint(const u64 x = 0) noexcept : a(x % Modulus) {}
  constexpr u64 &value() noexcept { return a; }
  constexpr const u64 &value() const noexcept { return a; }
  constexpr modint operator+(const modint rhs) const noexcept {
    return modint(*this) += rhs;
  }
  constexpr modint operator-(const modint rhs) const noexcept {
    return modint(*this) -= rhs;
  }
  constexpr modint operator*(const modint rhs) const noexcept {
    return modint(*this) *= rhs;
  }
  constexpr modint operator/(const modint rhs) const noexcept {
    return modint(*this) /= rhs;
  }
  constexpr modint &operator+=(const modint rhs) noexcept {
    a += rhs.a;
    if (a >= Modulus) {
      a -= Modulus;
    }
    return *this;
  }
  constexpr modint &operator-=(const modint rhs) noexcept {
    if (a < rhs.a) {
      a += Modulus;
    }
    a -= rhs.a;
    return *this;
  }
  constexpr modint &operator*=(const modint rhs) noexcept {
    a = a * rhs.a % Modulus;
    return *this;
  }
  constexpr modint &operator/=(modint rhs) noexcept {
    u64 exp = Modulus - 2;
    while (exp) {
      if (exp % 2) {
        *this *= rhs;
      }
      rhs *= rhs;
      exp /= 2;
    }
    return *this;
  }
};

int main() {
  const int MOD = 2019;

  string S;
  cin >> S;

  int N = LEN(S);

  reverse(ALL(S));

  int ten = 1;
  int tot = 0; // 累積和

  VI cnt(MOD); // 出現頻度

  ll ans = 0;
  REP(i, N) {
    cnt[tot]++; // (1)
    tot = (tot + (S[i] - '0') * ten) % MOD;
    ans += cnt[tot]; // (2)
    ten = ten * 10 % MOD;
  }

  // (1) cnt[tot]++;は前回ループ(i-1)のもの。
  // (2) ans +=
  // cnt[tot];は、前回までに出現したtotの数(cnt[tot])を加算している。今回の桁(i桁目)の分は含んでいない。
  //     今回の桁(i桁目)の分は次回ループの先頭((1)行)で出現頻度に加算され、次に同じtotが出現した際にcnt[tot]としてansに加算される。
  //     これにより初回出現時は、VI cntの初期値が0なのでansには何も加算されず、
  //     次回出現時は今までに出現した数が[l,
  //     r]範囲のlのパターン数として加算される。

  cout << ans << endl;

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;

typedef long long ll;
typedef vector<int> VI;
typedef vector<ll> VL;

const double PI = 3.14159265358979323846;

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define REP1(i, n) for (int i = 1; i <= (int)(n); i++)
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((int)(x).size())
#define LEN(x) ((int)(x).length())
#define ZERO(a) memset(a, 0, sizeof(a))

#define RAD(d) (PI * (d) / 180)
#define DEG(r) (180.0 * (r) / PI)

template <class T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}

template <class T> void dump(const vector<T> &v) {
  REP(i, SZ(v) - 1) { cout << v[i] << " "; }
  cout << v[SZ(v) - 1] << endl;
}

template <class T> void dump(int w, int h, const vector<T> &v) {
  REP(j, h) {
    REP(i, w - 1) { cout << v[j * w + i] << " "; }
    cout << v[j * w + w - 1] << endl;
  }
}

template <class T> T accumulate(const vector<T> &v) {
  T sum = 0;
  REP(i, SZ(v)) { sum += v[i]; }
  return sum;
}

template <class T> struct Matrix {
  T w, h;
  vector<T> A;
  Matrix(T w_, T h_) : w(w_), h(h_), A(w * h) {}
  T get(T x, T y) const { return A[y * w + x]; }
};

template <class T> void input(Matrix<T> &m) {
  REP(j, m.h) {
    REP(i, m.w) { cin >> m.A[j * m.w + i]; }
  }
}

template <class T> Matrix<T> prod(const Matrix<T> &a, const Matrix<T> &b) {
  Matrix<T> m(b.w, a.h);

  REP(j, m.h) {
    REP(i, m.w) {
      ll c = 0;
      REP(k, a.w) { c += a.A[j * a.w + k] * b.A[k * b.w + i]; }
      m.A[j * m.w + i] = c;
    }
  }

  return m;
}

void dump(const Matrix<ll> &m) {
  REP(j, m.h) {
    REP(i, m.w - 1) { printf("%lld ", m.A[j * m.w + i]); }
    printf("%lld\\n", m.A[j * m.w + m.w - 1]);
  }
}

void dump(const Matrix<double> &m) {
  REP(j, m.h) {
    REP(i, m.w - 1) { printf("%f ", m.A[j * m.w + i]); }
    printf("%f\\n", m.A[j * m.w + m.w - 1]);
  }
}

string &to_upper(string &s) {
  REP(i, s.length()) {
    if ('a' <= s[i] && s[i] <= 'z') {
      s[i] -= 32;
    }
  }

  return s;
}

string &to_lower(string &s) {
  REP(i, s.length()) {
    if ('A' <= s[i] && s[i] <= 'Z') {
      s[i] += 32;
    }
  }

  return s;
}

// すべての約数を列挙する
template <class T> vector<T> get_divisors(T n) {
  vector<T> ret;
  for (T i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      ret.push_back(i);
      if (i * i != n)
        ret.push_back(n / i);
    }
  }
  sort(ALL(ret));
  return ret;
}

// 1-sqrt(N)までの約数を列挙する
template <class T> vector<T> get_divisors2(T n) {
  vector<T> ret;
  for (T i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      ret.push_back(i);
    }
  }
  return ret;
}

inline int find_all(const string &s, const string &key) {
  int cnt = 0;
  int idx = 0;
  for (;;) {
    if (s.find(key, idx) == string::npos)
      break;

    cnt++;
    idx = LEN(key);
  }

  return cnt;
}

int main() {
  string words[99] = {
      "10095",  "100950", "102969", "104988", "107007", "109026", "111045",
      "113064", "115083", "117102", "119121", "12114",  "121140", "123159",
      "125178", "127197", "129216", "131235", "133254", "135273", "137292",
      "139311", "14133",  "141330", "143349", "145368", "147387", "149406",
      "151425", "153444", "155463", "157482", "159501", "16152",  "161520",
      "163539", "165558", "167577", "169596", "171615", "173634", "175653",
      "177672", "179691", "18171",  "181710", "183729", "185748", "187767",
      "189786", "191805", "193824", "195843", "197862", "199881", "2019",
      "20190",  "22209",  "24228",  "26247",  "28266",  "30285",  "32304",
      "34323",  "36342",  "38361",  "4038",   "40380",  "42399",  "44418",
      "46437",  "48456",  "50475",  "52494",  "54513",  "56532",  "58551",
      "6057",   "60570",  "62589",  "64608",  "66627",  "68646",  "70665",
      "72684",  "74703",  "76722",  "78741",  "8076",   "80760",  "82779",
      "84798",  "86817",  "88836",  "90855",  "92874",  "94893",  "96912",
      "98931",
  };

  string S;
  cin >> S;

  int total = 0;

  REP(i, 99) { total += find_all(S, words[i]); }

  cout << total << endl;

  return 0;
}