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;
#define REP(i, n) for(ll i = 0;i < n;i++)
#define ll long long
//#define MOD 1000000007
 
ll n,k,x,y,L,A,B,M,MOD;
 


class modint {
public:
  long long value;

  //+
	const modint operator + (modint mtmp) const{
    modint mdnt;
    mdnt.value=(this->value+mtmp.value);
    if (mdnt.value>=MOD)mdnt.value-=MOD;
    return mdnt;
	}
	const modint operator + (long long ltmp) const{
    modint mdnt;
    long long tmp=ltmp%MOD;
    if (tmp<0)tmp+=MOD;
    mdnt.value=(this->value+tmp);
    if (mdnt.value>=MOD)mdnt.value-=MOD;
    return mdnt;
	}

  //-
	const modint operator - (modint mtmp) const{
    modint mdnt;
    mdnt.value=(this->value-mtmp.value+MOD);
    if (mdnt.value>=MOD)mdnt.value-=MOD;
    return mdnt;
	}
	const modint operator - (long long ltmp) const{
    modint mdnt;
    long long tmp=ltmp%MOD;
    if (tmp<0)tmp+=MOD;
    mdnt.value=(this->value-tmp+MOD);
    if (mdnt.value>=MOD)mdnt.value-=MOD;
    return mdnt;
	}

  //*
	const modint operator * (modint mtmp) const{
    modint mdnt;
    mdnt.value=(this->value*mtmp.value)%MOD;
    return mdnt;
	}
	const modint operator * (long long ltmp) const{
    modint mdnt;
    long long ltmpm=ltmp%MOD;
    if (ltmpm<0)ltmpm+=MOD;
    mdnt.value=(this->value*ltmpm)%MOD;
    return mdnt;
	}

  ///
	const modint operator / (long long ltmp) const{
    modint mdnt;
    long long ltmpm=ltmp%MOD;
    if (ltmpm<0)ltmpm+=MOD;
    long long mdnv=this->value;

    long long x0=MOD,x1=ltmpm,x2,n0=0LL,n1=1LL,n2,t=mdnv%ltmpm,m,ans;
    if (t==0){
      mdnt.value=mdnv/ltmpm;
      return mdnt;
    } 
      for(int i=0;i<900;i++){
        m=x0/x1;
        x2=x0-x1*m;
        n2=(n0-m*n1)%MOD;
        if (x2==1){
          ans=(n2+MOD)%MOD;
          break;
        }
        x0=x1;x1=x2;
        n0=n1;n1=n2;
      }

    mdnt.value=(mdnv+((t*ans)%MOD)*ltmpm-t)/ltmpm;
    return mdnt;
  }
	const modint operator / (modint mtmp) const{
    modint mdnt;
    //mdnt.value=this->value;
    return (*this)/mtmp.value;
	}
  
  //%
	const modint operator % (long long ltmp) const{
    modint mdnt;
    mdnt.value=(this->value%ltmp);
    return mdnt;
	}


  //代入演算子のオーバーロード
  modint &operator = (const modint mtmp) 
  {
      this->value = mtmp.value;
      return *this;
  }
  modint &operator = (const long long ltmp) 
  {
      this->value = ltmp%MOD;
      if ((this->value)<0)this->value+=MOD;
      return *this;
  }
  
  //+=
  modint &operator += (const modint mtmp) 
  {
      this->value = (this->value+mtmp.value);
      if (this->value>=MOD)this->value-=MOD;
      return *this;
  }
  modint &operator += (long long ltmp) 
  {
      long long tmp=ltmp%MOD;
      if (tmp<0)tmp+=MOD;
      this->value=(this->value+tmp);
      if (this->value>=MOD)this->value-=MOD;
      return *this;
  }

  //-=
  modint &operator -= (const modint mtmp) 
  {
      this->value = (this->value-mtmp.value+MOD);
      if (this->value>=MOD)this->value-=MOD;
      return *this;
  }
  modint &operator -= (long long ltmp) 
  {
      long long tmp=ltmp%MOD;
      if (tmp<0)tmp+=MOD;
      this->value=(this->value-tmp+MOD);
      if (this->value>=MOD)this->value-=MOD;
      return *this;
  }
  //*=
  modint &operator *= (const modint mtmp) 
  {
      this->value = this->value*mtmp.value%MOD;
      return *this;
  }
  modint &operator *= (long long ltmp) 
  {
      this->value = this->value*(ltmp%MOD)%MOD;
      if (this->value<0)this->value+=MOD;
      return *this;
  }  
  ///=
  modint &operator /= (const modint mtmp) 
  {
      modint tmp=(*this)/mtmp.value;
      this->value = tmp.value;
      return *this;
  }
  modint &operator /= (long long ltmp) 
  {
      modint tmp=(*this)/ltmp;
      this->value = tmp.value;
      return *this;
  }
  //%=
  modint &operator %= (long long ltmp) 
  {
      this->value%=ltmp;
      return *this;
  }


  //exp関数
  //aのn乗 mod c
  modint exp(long long n){
    long long ans=1LL,aa=this->value,beki=n;
    for(int i=0;i<64;i++){
      if (beki%2==1) ans=ans*aa%MOD;
      aa=aa*aa%MOD;
      beki/=2;
      if (beki==0)break;
    }
    modint mdnt;
    mdnt.value=ans;
    return mdnt;
  }
  //friend ostream& operator << (ostream& os, const modint& m);
};

ostream& operator << (ostream& os, const modint& m)
{
  os << m.value;
  return os;
}
 
using vi = vector<modint>; // intの1次元の型に vi という別名をつける
using vvi = vector<vi>; // intの2次元の型に vvi という別名をつける
 
ll mylog10(unsigned long long a){
	unsigned long long w=1ULL;
	for(;w<=a;w*=10ULL){
	}
	return (ll)(w/10ULL);
}
 
void matmul(vvi &C,vvi A,vvi B)
{
	REP(i,k){	
		REP(j,k){	
			C[i][j]=0;
			REP(l,k){
				C[i][j]+=A[l][j]*B[i][l];
			}
		}
	}
}
 
void matpow(vvi &matans,vvi &imat,ll num){
  vvi updmat(k, vi(k));  // k * k の正方行列
  REP(i,k) matans[i][i]=1;//単位行列 I
  REP(i,k)REP(j,k)updmat[i][j]=imat[i][j];
	while(num)
	{
		if (num%2==1)
		{
			matmul(matans,matans,updmat);
		}
		num/=2;
		matmul(updmat,updmat,updmat);
	}
	return;
}
 
 
int main(){
  cin >> L >> A >> B>>M;
  MOD=M;
  modint ans;
  ans=0;
  ll lasts;
  k=3;
  vvi mat2d(k, vi(k));  // k * k の正方行列
  mat2d[0][0]=1;
  mat2d[2][0]=0;
  mat2d[0][0]=1;
  modint e,sm;
  sm=1;
	for (int i=0;i<999;i++){
		lasts=(L-1)*B+A;
		ll lowL=(mylog10(lasts)-1-A)/B;
		if ((mylog10(lasts)-1-A)<0)
		{
			lowL=-1;
		}
		ll Lnmu=L-1-lowL;
		mat2d[1][0]=(mylog10(lasts)%M*10LL);
		mat2d[2][2]=(mylog10(lasts)%M*10LL);
		mat2d[1][1]=(mylog10(lasts)%M*10LL);
		mat2d[2][1]=(-(B%M)+M)*((mylog10(lasts)%M*10LL)%M);
    vvi ansmat(k, vi(k));  // k * k の正方行列
		matpow(ansmat,mat2d,Lnmu-1);
		modint pans;
		pans=(ansmat[0][0]*(lasts)+ansmat[1][0]*(lasts-B)+ansmat[2][0]);
		ans=ans+pans*sm;
		e=(mylog10(lasts)%M*10LL);
		sm=sm*e.exp(Lnmu);
		L=lowL+1;
		if (L==0)break;
	}
  cout<<ans<<endl;
  return 0;
}