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# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using SB = System.Text.StringBuilder;
//using System.Threading.Tasks;
//using System.Text.RegularExpressions;
//using System.Globalization;
//using System.Diagnostics;
using static System.Console;
using System.Numerics;
using static System.Math;
using pair = Pair<int, int>;

class Program
{
    static void Main()
    {
        //SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
        new Program().solve();
        Out.Flush();
    }
    readonly Scanner cin = new Scanner();
    readonly int[] dd = { 0, 1, 0, -1, 0 }; //→↓←↑
    readonly int mod = 1000000007;
    readonly int dom = 998244353;
    bool chmax<T>(ref T a, T b) where T : IComparable<T> { if (a.CompareTo(b) < 0) { a = b; return true; } return false; }
    bool chmin<T>(ref T a, T b) where T : IComparable<T> { if (b.CompareTo(a) < 0) { a = b; return true; } return false; }

    void solve()
    {
        var L = cin.nextlong;
        var A = cin.nextlong;
        var B = cin.nextlong;
        var M = cin.nextint;

        var cnt = new long[18];
        var sum = new long[18];
        //(k+1)桁について考える
        long BASE = 1;
        for (int k = 0; k < 18; k++, BASE *= 10)
        {
            if (BASE * 10 <= A)
            {
                continue;
            }
            if (A + B * (L - 1) < BASE)
            {
                break;
            }

            var left = (BASE - A + B - 1) / B;
            if (left < 0) left = 0;
            var right = (BASE * 10 - A - 1) / B;
            if (right >= L) right = L - 1;

            if (right < left) continue;
            cnt[k] = right - left + 1;

            //初項
            var first = A + B * left;
            var last = A + B * right;


            sum[k] += first % M * F(cnt[k] - 1, BASE * 10 % M, M) % M;
            sum[k] += B % M * G(cnt[k] - 1, BASE * 10 % M, M) % M;

            sum[k] %= M;
            //WriteLine($"first={first} last={last} sum={sum[k]} cnt={cnt[k]}");
            //WriteLine($"right={first % M * F(cnt[k] - 1, BASE * 10 % M, M) % M} F={ F(cnt[k] - 1, BASE * 10 % M, M)}");
            //WriteLine($"left={B % M * G(cnt[k] - 1, BASE * 10 % M, M) % M} G={ G(cnt[k] - 1, BASE * 10 % M, M)}");
        }

        long ans = 0;
        long before = 1;
        for (int k = 18 - 1; k >= 0; k--)
        {
            ans += sum[k] * before % M;
            before = before * powmod(powmod(10, k + 1, M), cnt[k], M) % M;
        }
        WriteLine(ans % M);

    }
    long G(long L, long BASE, long mod)
    {
        if (L == 0) return 0;
        if (L % 2 == 1)
        {
            long g = G(L / 2, BASE, mod);
            long f = F(L / 2, BASE, mod);

            return (g * (powmod(BASE, L / 2 + 1, mod) + 1) + (L / 2 + 1) % mod * f) % mod;
        }
        else
        {
            return (L + G(L - 1, BASE, mod) * BASE) % mod;
        }
    }
    long F(long L, long BASE, long mod)
    {
        if (L == 0) return 1;
        if (L % 2 == 1)
        {
            long d = F(L / 2, BASE, mod);
            return (d * powmod(BASE, L / 2 + 1, mod) + d) % mod;
        }
        else
        {
            return (BASE * F(L - 1, BASE, mod) + 1) % mod;
        }
    }
    //a^b(mod p) solution works in O(logb).
    long powmod(long a, long b, long p)
    {
        if (b == 0) return 1;
        if (b % 2 == 0)
        {
            long d = powmod(a, b / 2, p);
            return d * d % p;
        }
        else
        {
            return a * powmod(a, b - 1, p) % p;
        }
    }

}


static class Ex
{
    public static void join<T>(this IEnumerable<T> values, string sep = " ") => WriteLine(string.Join(sep, values));
    public static string concat<T>(this IEnumerable<T> values) => string.Concat(values);
    public static string reverse(this string s) { var t = s.ToCharArray(); Array.Reverse(t); return t.concat(); }

    public static int lower_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) < 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
    public static int upper_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) <= 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
}

class Pair<T, U> : IComparable<Pair<T, U>> where T : IComparable<T> where U : IComparable<U>
{
    public T f; public U s;
    public Pair(T f, U s) { this.f = f; this.s = s; }
    public int CompareTo(Pair<T, U> a) => f.CompareTo(a.f) != 0 ? f.CompareTo(a.f) : s.CompareTo(a.s);
    public override string ToString() => $"{f} {s}";
}

class Scanner
{
    string[] s; int i;
    readonly char[] cs = new char[] { ' ' };
    public Scanner() { s = new string[0]; i = 0; }
    public string[] scan => ReadLine().Split();
    public int[] scanint => Array.ConvertAll(scan, int.Parse);
    public long[] scanlong => Array.ConvertAll(scan, long.Parse);
    public double[] scandouble => Array.ConvertAll(scan, double.Parse);
    public string next
    {
        get
        {
            if (i < s.Length) return s[i++];
            string st = ReadLine();
            while (st == "") st = ReadLine();
            s = st.Split(cs, StringSplitOptions.RemoveEmptyEntries);
            i = 0;
            return next;
        }
    }
    public int nextint => int.Parse(next);
    public long nextlong => long.Parse(next);
    public double nextdouble => double.Parse(next);
}