#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) { return to_string(n).length(); }

// 初項 a 公差 b 、要素数が l (s0, s1, ..., sl-1), の等差数列において、
// 桁数が k のときの初項 x が、元の等差数列でいうと何番目にあたるかを求める(基数は 0)
// 桁数が A より少ないもしくは S(L-1) より大きい場合は -1 が返る
ll GetFirstIndex(ll a, ll b, ll l, ll k) {
    if(LLINF / b > (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;
}

// 初項 a 公差 b 、要素数が l (s0, s1, ..., sl-1), の等差数列において、
// 桁数が k のときの初項 x を求める
// 桁数が a より少ないもしくは S(l-1) より大きい場合は -1 が返る
mint GetFirstTerm(ll a, ll b, ll l, ll k) {
    ll i = GetFirstIndex(a, b, l, k);
    if(i < 0) { return -1; }
    return mint(A) + mint(B) * mint(i);
}

// 初項 a 公差 b 、要素数が l (s0, s1, ..., sl-1), の等差数列において、
// 桁数が k のものが、元の等差数列でいくつ出てくるかを求める
ll GetCnt(ll a, ll b, ll l, ll k) {
    if(GetFirstIndex(a, b, l, k) < 0) { return 0; }
    ll ub = GetFirstIndex(a, b, l, k+1);
    if(ub == -1) { ub = l; }
    return ub - GetFirstIndex(a, b, l, k);
}

// 初項 a, 公比 b の等比数列の第 n 項(1-indexed)までの和を求めます
// mod は素数でなくともいけます
// O(log n)
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
// O(log n)
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(A, B, L, k);
        first_term[k] = GetFirstTerm(A, B, L, 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;
}


Measured memory_bytes: 256