Problem:
Score : 600 points

Problem Statement

There is an arithmetic progression with L terms: s_0, s_1, s_2, ... , s_{L-1}.

The initial term is A, and the common difference is B. That is, s_i = A + B \times i holds.

Consider the integer obtained by concatenating the terms written in base ten without leading zeros. For example, the sequence 3, 7, 11, 15, 19 would be concatenated into 37111519. What is the remainder when that integer is divided by M?

Constraints

All values in input are integers.

1 \leq L, A, B < 10^{18}

2 \leq M \leq 10^9

All terms in the arithmetic progression are less than 10^{18}.

Input

Input is given from Standard Input in the following format:

L A B M

Output

Print the remainder when the integer obtained by concatenating the terms is divided by M.

Sample Input 1

5 3 4 10007

Sample Output 1

5563

Our arithmetic progression is 3, 7, 11, 15, 19, so the answer is 37111519 mod 10007, that is, 5563.

Sample Input 2

4 8 1 1000000

Sample Output 2

891011

Sample Input 3

107 10000000000007 1000000000000007 998244353

Sample Output 3

39122908

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define ALL(name) name.begin(),name.end()
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))

const ll LLINF = (1LL<<62);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
#define MAX_N 100010

ll L, A, B, M;

struct mint {
    ll x;
    mint(ll x = 0) : x(x % M) {}
    mint& operator += (const mint a) {
        if ( (x += a.x) >= M) { x -= M; }
        return *this;
    }
    mint& operator -= (const mint a) {
        if ( (x += M - a.x) >= M) { x -= M; }
        return *this;
    }
    mint& operator *= (const mint a) {
        (x *= a.x) %= M;
        return *this;
    }
    mint operator + (const mint a) const {
        mint res(*this);
        return res += a;
    }
    mint operator - (const mint a) const {
        mint res(*this);
        return res -= a;
    }
    mint operator * (const mint a) const {
        mint res(*this);
        return res *= a;
    }
};

vector<mint> first_term;    // 桁数 i のものの等差数列の初項
vector<ll> cnt;             // 桁数 i のものが等差数列に登場する数
vector<ll> pow_ten;         // 10^i を求める。 i は[0, 20)

// x の n 乗を繰り返し二乗法で計算
// 余りをとりたいなら mint を使用すること
template <typename T> inline T power(T x, uint64_t n, T e = 1) { T r = e; while (n > 0) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; }

// 10^n を O(1) で返す
static inline ll Pow(ll n) { return pow_ten[n]; }
// 数字 n の桁数を返す
static inline ll DigitCnt(ll n) {
    string s = to_string(n);
    return s.length();
}

// 桁数が k のときの初項 x が、元の等差数列でいうと何番目にあたるかを求める(基数は 0)
// 桁数が A より少ないもしくは S(L-1) より大きい場合は -1 が返る
ll GetFirstIndex(ll k) {
    ll ab = A + B;
    // 掛け算の場合…割り算 if を使って判定できる
    if(LLINF / ab > (L - 1)) {
        // OK
        if(k < DigitCnt(A)) { return -1; }
        else if(k == DigitCnt(A)) { return 0; }
        else if(k > A + B * (L-1)) { return -1; }
    } else {
        // overflow
        if(k < DigitCnt(A)) { return -1; }
        else if(k == DigitCnt(A)) { return 0; }
    }

    // Si = A + B * i なので、 i < (10^(k-1) - A) / B のときの i が、
    // k-1 桁のときの最大の i, なのでその i+1 が答え
    ll i = (Pow(k-1) - A) / B;
    if(i <= 0) { i = 1; }
    else if((Pow(k-1) - A) % B != 0) { i++; }

    if(L <= i) { return -1; }

    return i;
}

// 桁数が k のときの初項 x を求める
// 桁数が A より少ないもしくは S(L-1) より大きい場合は -1 が返る
mint GetFirstTerm(ll k) {
    ll i = GetFirstIndex(k);
    if(i < 0) { return -1; }
    return mint(A) + mint(B) * mint(i);
}

// 桁数が k のものが、元の等差数列でいくつ出てくるかを求める
ll GetCnt(ll k) {
    if(GetFirstIndex(k) < 0) { return 0; }
    ll ub = GetFirstIndex(k+1);
    if(ub == -1) { ub = L; }
    return ub - GetFirstIndex(k);
}

// 初項 a, 公比 b の等比数列の第 n 項(1-indexed)までの和を求めます
// mod は素数でなくともいけます
mint GeoProSum(mint a, mint b, uint64_t n) {
    // 第 1 項までの和から初めて、第 n 項になるまで遷移を繰り返す
    if (n == 1) { return a; }
    if(n % 2 == 0) {
        n /= 2;
        return GeoProSum(a, b, n) * (power(b, n) + 1);
    }
    else {
        n--;
        return GeoProSum(a, b, n) + power(b, n);
    }
}


// 初項 0, 公差 1 の等差数列と、初項 Tn^N-1 公比Tn-1 の積の第 N 項(1-indexed) までの和
// Tn: 10^k % M
mint AriGeoProSum(ll k, mint Tn, uint64_t n) {
    if(n == 1) { return 0; }
    if(n % 2 == 0) {
        n /= 2;
        return AriGeoProSum(k, Tn, n) * (power(Tn, n) + 1) + mint(n) * GeoProSum(1, Tn, n);
    }
    else {
        n--;
        return AriGeoProSum(k, Tn, n) + GeoProSum(1, Tn, n);
    }
}

signed main() {
    cin.tie(0); cout.tie(0);
    ios::sync_with_stdio(false);

    // pow_ten の作成
    pow_ten.resize(20);
    pow_ten[0] = 1;
    for(int i = 1; i < 20; ++i) { pow_ten[i] = pow_ten[i-1] * 10; }

    cin >> L >> A >> B >> M;

    // 各桁の初項と要素数を求める
    cnt.resize(20);
    first_term.resize(20);
    for(int k = 1; k <= 18; ++k) {
        cnt[k] = GetCnt(k);
        first_term[k] = GetFirstTerm(k);
    }

    mint ans = 0;
    for(int k = 1; k <= 18; ++k) {
        mint Tn = power(mint(10), k);

        mint tmp_x = first_term[k];
        if(cnt[k] == 0) { continue; }
        // 初項 1 , 公比 10^k 等比数列の第 N 項(1-indexed)までの和
        tmp_x *= GeoProSum(1, Tn, cnt[k]);

        // 初項 0, 公差 1 の等差数列と、初項 (10^k)^N-1 公比(10^k)-1 の積の第 N 項(1-indexed) までの和
        mint tmp_y = B;
        tmp_y *= AriGeoProSum(k, Tn, cnt[k]);

        tmp_x += tmp_y;

        if(k > 1) {
            mint p = power(Tn, cnt[k]);
            ans *= p;
        }

        ans += tmp_x;
    }

    printf("%lld\n", ans.x);

    return 0;
}