Problem p03016 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define REP(i, n) for (int i = 0, _n = (int)(n); i < _n; ++i)
#define ALL(v) (v).begin(), (v).end()
#define CLR(t, v) memset(t, (v), sizeof(t))
template <class T1, class T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &a) {
  return os << "(" << a.first << "," << a.second << ")";
}
template <class T> void pv(T a, T b) {
  for (T i = a; i != b; ++i)
    cout << (*i) << " ";
  cout << endl;
}
template <class T> void chmin(T &a, const T &b) {
  if (a > b)
    a = b;
}
template <class T> void chmax(T &a, const T &b) {
  if (a < b)
    a = b;
}

ll MOD;

#define SZ(v) ((int)(v).size())
typedef vector<ll> Array;
typedef vector<Array> Matrix;

Matrix zero(int N) { return Matrix(N, Array(N)); }

Matrix identity(int N) {
  Matrix A = zero(N);
  REP(i, N) A[i][i] = 1;
  return A;
}

Array mul(const Matrix &A, const Array &x) {
  const int N = SZ(A);
  const int M = SZ(A[0]);
  Array y(N);
  REP(i, N) REP(j, M) {
    y[i] += A[i][j] * x[j];
    y[i] %= MOD;
  }
  return y;
}

Matrix mul(const Matrix &A, const Matrix &B) {
  const int N = SZ(A);
  const int P = SZ(A[0]);
  const int M = SZ(B[0]);
  Matrix C(N, Array(M));
  REP(i, N) REP(j, M) REP(k, P) {
    C[i][j] += A[i][k] * B[k][j];
    if (C[i][j] >= MOD)
      C[i][j] %= MOD;
  }
  return C;
}

Matrix pow(Matrix A, ll b) {
  Matrix C = identity(SZ(A));
  while (b > 0) {
    if ((b & 1) == 1)
      C = mul(C, A);
    A = mul(A, A);
    b >>= 1;
  }
  return C;
}

void print(const Matrix &A) {
  REP(i, SZ(A)) {
    REP(j, SZ(A[0])) { cout << A[i][j] << " "; }
    cout << endl;
  }
  cout << "---------------------" << endl;
}

ll mod_pow(ll a, ll b, ll p) {
  ll res = 1;
  while (b > 0) {
    if (b & 1)
      res = (res * a) % p;
    a = (a * a) % p;
    b >>= 1;
  }
  return res;
}

int getKeta(ll x) {
  int res = 0;
  while (x > 0) {
    x /= 10;
    res++;
  }
  return res;
}

// k 桁になる要素の添え字の両端の添え字
pair<ll, ll> ketaRange(ll A, ll B, ll L, int k) {
  ll lb, ub;
  {
    ll lo = -1;
    ll hi = L;
    while (hi - lo > 1) {
      ll mid = (hi + lo) / 2;
      int keta = getKeta(A + B * mid);
      if (keta < k) {
        lo = mid;
      } else {
        hi = mid;
      }
    }
    lb = hi;
  }
  {
    ll lo = -1;
    ll hi = L;
    while (hi - lo > 1) {
      ll mid = (hi + lo) / 2;
      int keta = getKeta(A + B * mid);
      if (keta <= k) {
        lo = mid;
      } else {
        hi = mid;
      }
    }
    ub = hi;
  }
  return {lb, ub};
}

ll solve(ll A, ll B, ll L) {
  ll res = 0;
  for (int k = 1; k <= 18; k++) {
    ll from, to;
    tie(from, to) = ketaRange(A, B, L, k);
    ll n = to - from;
    if (n == 0)
      continue;
    // cout << k << ":" << from << " " << to << endl;
    const ll TEN = pow(10, k);

    Matrix M = zero(3);
    M[0][0] = TEN;
    M[0][1] = 1;
    M[1][1] = 1;
    M[1][2] = 1;
    M[2][2] = 1;
    Array b = Array({0, A + from * B, B});

    REP(i, 3) REP(j, 3) M[i][j] %= MOD;
    REP(i, b.size()) b[i] %= MOD;

    M = pow(M, n);
    Array R = mul(M, b);
    // cout << "k=" << k << ", n="<< n << ", res=" << R[0] << endl;
    if (k * n < 0)
      while (true)
        ;
    res = (res * mod_pow(10, k * n, MOD) % MOD + R[0] % MOD) % MOD;
  }
  return res;
}

int main2() {
  ll L, A, B;
  cin >> L >> A >> B >> MOD;
  ll ans = solve(A, B, L);
  cout << ans << endl;
  return 0;
}

int main() {
  // ll A = 1;
  // ll B = 170;
  // ll L = 30;
  // REP(i, L) {
  //   ll s = A + B * i;
  //   cout << getKeta(s) << " " << s << endl;
  // }
  // for (int k = 1; k <= 10; k++) {
  //   cout << k << ":" << ketaRange(A, B, L, k) << endl;
  // }
  // return 0;

#ifdef LOCAL
  for (; !cin.eof(); cin >> ws)
#endif
    main2();
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define REP(i, n) for (int i = 0, _n = (int)(n); i < _n; ++i)
#define ALL(v) (v).begin(), (v).end()
#define CLR(t, v) memset(t, (v), sizeof(t))
template <class T1, class T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &a) {
  return os << "(" << a.first << "," << a.second << ")";
}
template <class T> void pv(T a, T b) {
  for (T i = a; i != b; ++i)
    cout << (*i) << " ";
  cout << endl;
}
template <class T> void chmin(T &a, const T &b) {
  if (a > b)
    a = b;
}
template <class T> void chmax(T &a, const T &b) {
  if (a < b)
    a = b;
}

ll MOD;

#define SZ(v) ((int)(v).size())
typedef vector<ll> Array;
typedef vector<Array> Matrix;

Matrix zero(int N) { return Matrix(N, Array(N)); }

Matrix identity(int N) {
  Matrix A = zero(N);
  REP(i, N) A[i][i] = 1;
  return A;
}

Array mul(const Matrix &A, const Array &x) {
  const int N = SZ(A);
  const int M = SZ(A[0]);
  Array y(N);
  REP(i, N) REP(j, M) {
    y[i] += A[i][j] * x[j];
    y[i] %= MOD;
  }
  return y;
}

Matrix mul(const Matrix &A, const Matrix &B) {
  const int N = SZ(A);
  const int P = SZ(A[0]);
  const int M = SZ(B[0]);
  Matrix C(N, Array(M));
  REP(i, N) REP(j, M) REP(k, P) {
    C[i][j] += A[i][k] * B[k][j];
    if (C[i][j] >= MOD)
      C[i][j] %= MOD;
  }
  return C;
}

Matrix pow(Matrix A, ll b) {
  Matrix C = identity(SZ(A));
  while (b > 0) {
    if ((b & 1) == 1)
      C = mul(C, A);
    A = mul(A, A);
    b >>= 1;
  }
  return C;
}

void print(const Matrix &A) {
  REP(i, SZ(A)) {
    REP(j, SZ(A[0])) { cout << A[i][j] << " "; }
    cout << endl;
  }
  cout << "---------------------" << endl;
}

ll mod_pow(ll a, ll b, ll p) {
  ll res = 1;
  while (b > 0) {
    if (b & 1)
      res = (res * a) % p;
    a = (a * a) % p;
    b >>= 1;
  }
  return res;
}

int getKeta(ll x) {
  int res = 0;
  while (x > 0) {
    x /= 10;
    res++;
  }
  return res;
}

// k 桁になる要素の添え字の両端の添え字
pair<ll, ll> ketaRange(ll A, ll B, ll L, int k) {
  ll lb, ub;
  {
    ll lo = -1;
    ll hi = L;
    while (hi - lo > 1) {
      ll mid = (hi + lo) / 2;
      int keta = getKeta(A + B * mid);
      if (keta < k) {
        lo = mid;
      } else {
        hi = mid;
      }
    }
    lb = hi;
  }
  {
    ll lo = -1;
    ll hi = L;
    while (hi - lo > 1) {
      ll mid = (hi + lo) / 2;
      int keta = getKeta(A + B * mid);
      if (keta <= k) {
        lo = mid;
      } else {
        hi = mid;
      }
    }
    ub = hi;
  }
  return {lb, ub};
}

ll solve(ll A, ll B, ll L) {
  ll res = 0;
  for (int k = 1; k <= 18; k++) {
    ll from, to;
    tie(from, to) = ketaRange(A, B, L, k);
    ll n = to - from;
    if (n == 0)
      continue;
    // cout << k << ":" << from << " " << to << endl;
    const ll TEN = pow(10, k);

    Matrix M = zero(3);
    M[0][0] = TEN;
    M[0][1] = 1;
    M[1][1] = 1;
    M[1][2] = 1;
    M[2][2] = 1;
    Array b = Array({0, A + from * B, B});

    REP(i, 3) REP(j, 3) M[i][j] %= MOD;
    REP(i, b.size()) b[i] %= MOD;

    M = pow(M, n);
    Array R = mul(M, b);
    // cout << "k=" << k << ", n="<< n << ", res=" << R[0] << endl;
    res = (res * mod_pow(TEN % MOD, n, MOD) % MOD + (R[0] % MOD)) % MOD;
  }
  return res;
}

int main2() {
  ll L, A, B;
  cin >> L >> A >> B >> MOD;
  ll ans = solve(A, B, L);
  cout << ans << endl;
  return 0;
}

int main() {
  // ll A = 1;
  // ll B = 170;
  // ll L = 30;
  // REP(i, L) {
  //   ll s = A + B * i;
  //   cout << getKeta(s) << " " << s << endl;
  // }
  // for (int k = 1; k <= 10; k++) {
  //   cout << k << ":" << ketaRange(A, B, L, k) << endl;
  // }
  // return 0;

#ifdef LOCAL
  for (; !cin.eof(); cin >> ws)
#endif
    main2();
  return 0;
}