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 Rust (1.42.0) (judge verdict: Accepted)

define_runtime_modint!(MInt; Modulus with MOD: i32);

use num::One;

fn main() {
	let mut s = String::new();
	use std::io::Read;
	std::io::stdin().read_to_string(&mut s).unwrap();
	let mut s = s.split_whitespace();
	let l: i64 = s.next().unwrap().parse().unwrap();
	let a: i64 = s.next().unwrap().parse().unwrap();
	let b: i64 = s.next().unwrap().parse().unwrap();
	let m: i32 = s.next().unwrap().parse().unwrap();
	let ans = Modulus::with(m, || {
		let mut matrix = SquareMatrix::identity(3);
		let mut l = l;
		let mut cur = a;
		while l > 0 {
			let tenp = next_power_of_ten(cur);
			let cnt = (tenp - 1 - cur) / b + 1;
			let exp = std::cmp::min(l, cnt);
			cur += cnt * b;
			let mut mat = SquareMatrix::new(3);
			mat[(0, 0)] = MInt::from(tenp);
			mat[(0, 1)] = MInt::one();
			mat[(1, 1)] = MInt::one();
			mat[(1, 2)] = MInt::from(b);
			mat[(2, 2)] = MInt::one();
			matrix = SquareMatrix::pow(mat, exp as u64) * matrix;
			l -= cnt;
		}
		matrix[(0, 1)] * MInt::from(a) + matrix[(0, 2)]
	});
	println!("{}", ans);
}

pub fn prev_power_of_ten(n: i64) -> i64 {
	let mut r = 1;
	let mut n = n;
	while {
		n /= 10;
		n > 0
	} {
		r *= 10;
	}
	r
}

pub fn next_power_of_ten(n: i64) -> i64 {
	prev_power_of_ten(n) * 10
}

#[derive(Clone)]
pub struct SquareMatrix<T> {
	elem: Vec<T>,
	size: usize,
}

impl<T> SquareMatrix<T>
where
	T: Clone,
{
	pub fn new(size: usize) -> Self
	where
		T: Default,
	{
		Self {
			size,
			elem: vec![T::default(); size * size],
		}
	}

	pub fn size(&self) -> usize {
		self.size
	}

	pub fn zeros(size: usize) -> Self
	where
		T: num::Zero,
	{
		Self {
			size,
			elem: vec![T::zero(); size * size],
		}
	}

	pub fn identity(size: usize) -> Self
	where
		T: num::Zero + num::One,
	{
		let mut elem = vec![T::zero(); size * size];
		for i in (0..size * size).step_by(size + 1) {
			elem[i] = T::one();
		}
		Self { size, elem }
	}

	pub fn get(&self, i: usize, j: usize) -> Option<&T> {
		if i < self.size && j < self.size() {
			unsafe { Some(self.elem.get_unchecked(i * self.size() + j)) }
		} else {
			None
		}
	}

	pub fn get_mut(&mut self, i: usize, j: usize) -> Option<&mut T> {
		if i < self.size && j < self.size() {
			unsafe {
				let size = self.size();
				Some(self.elem.get_unchecked_mut(i * size + j))
			}
		} else {
			None
		}
	}

	pub unsafe fn get_unchecked(&self, i: usize, j: usize) -> &T {
		self.elem.get_unchecked(i * self.size() + j)
	}

	pub unsafe fn get_unchecked_mut(&mut self, i: usize, j: usize) -> &mut T {
		let size = self.size();
		self.elem.get_unchecked_mut(i * size + j)
	}

	pub fn pow<U>(matrix: Self, exp: U) -> Self
	where
		T: num::Zero + num::One + std::ops::Add<Output = T> + std::ops::Mul<Output = T>,
		U: num::Unsigned + num::Integer,
	{
		let mut mat = matrix;
		let mut n = exp;
		let mut r = Self::identity(mat.size());
		while n > U::zero() {
			if n.is_odd() {
				r = r * &mat;
			}
			mat = &mat * &mat;
			n = n / (U::one() + U::one());
		}
		r
	}
}

impl<T> std::ops::Index<(usize, usize)> for SquareMatrix<T> {
	type Output = T;
	fn index(&self, index: (usize, usize)) -> &Self::Output {
		assert!(index.0 < self.size && index.1 < self.size);
		unsafe { self.elem.get_unchecked(index.0 * self.size + index.1) }
	}
}

impl<T> std::ops::IndexMut<(usize, usize)> for SquareMatrix<T> {
	fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
		assert!(index.0 < self.size && index.1 < self.size);
		unsafe { self.elem.get_unchecked_mut(index.0 * self.size + index.1) }
	}
}

macro_rules! impl_ {
	($trait:ident:$fn:ident for $type:ty) => {
		impl_!($type; $trait:$fn);
		impl_!($type; $trait<&>:$fn);
		impl_!($type; <&> $trait:$fn);
		impl_!($type; <&> $trait<&>:$fn);
	};

	($type:ty; $(<$ref_self:tt>)? Mul$(<$($ref_rhs:tt)?>)?:$fn:ident) => {
		impl<T> std::ops::Mul<$($($ref_rhs)?)?$type> for $($ref_self)? $type
		where
			T: Clone + num::Zero + std::ops::Add<Output = T> + std::ops::Mul<Output = T>,
		{
			type Output = $type;
			fn $fn(self, rhs: $($($ref_rhs)?)?$type) -> Self::Output {
				assert_eq!(self.size(), rhs.size());

				let mut r = <$type>::zeros(self.size());

				for i in 0..self.size() {
					for k in 0..rhs.size() {
						for j in 0..rhs.size() {
							unsafe {
								*r.get_unchecked_mut(i, j) = r.get_unchecked(i, j).clone() + self.get_unchecked(i, k).clone() * rhs.get_unchecked(k, j).clone();
							}
						}
					}
				}
				r
			}
		}
	};
}

impl_!(Mul:mul for SquareMatrix<T>);

pub mod traits {
	pub mod consts {
		pub trait Constant: super::marker::Unsafe {
			type Type;
			fn value() -> Self::Type;
		}
	}
	pub mod marker {
		pub unsafe trait Unsafe {}
	}

	pub mod integer {
		pub trait SizeOrder<T> {
			type LargerType;
			type SmallerType;
		}

		pub trait IntoLarger {
			type LargerType;
		}

		macro_rules! impl_ {
			($i0:ty:$u0:ty, $($is:ty:$us:ty),+) => {
				impl_![imp $i0:$u0];
				impl_![imp $i0];
				impl_![imp $u0];
				$(impl_![imp $i0:$u0, $is:$us];)+
				impl_![$($is:$us),+];
			};

			($i:ty:$u:ty) => {
				impl_![imp $i:$u];
				impl_![imp $i];
				impl_![imp $u];
			};

			(imp $t:ty) => {
				impl_![imp $t | $t, $t:$t];
			};

			(imp $i:ty:$u:ty) => {
				impl_![imp $u | $i, $u:$i];
				impl_![imp $i | $u, $u:$i];
			};

			(imp $i0:ty:$u0:ty, $i1:ty:$u1:ty) => {
				impl_![imp $i1 | $i0, $i1:$i0];
				impl_![imp $u1 | $u0, $u1:$u0];
				impl_![imp $i1 | $u0, $i1:$u0];
				impl_![imp $u1 | $i0, $u1:$i0];
				impl_![imp $i0 | $i1, $i1:$i0];
				impl_![imp $u0 | $u1, $u1:$u0];
				impl_![imp $u0 | $i1, $i1:$u0];
				impl_![imp $i0 | $u1, $u1:$i0];
			};

			(imp $target:ty | $self:ty, $large:ty:$small:ty) => {
				impl SizeOrder<$target> for $self {
					type LargerType = $large;
					type SmallerType = $small;
				}
			};

			(lt ptr; $($is:ty:$us:ty),+) => {
				$(impl_![imp $is:$us, isize:usize];)+
			};
			(eq ptr; $($is:ty:$us:ty),+) => {
				impl_![isize:usize];
				$(
					impl_![imp $is | isize, $is:isize];
					impl_![imp $us | isize, $us:isize];
					impl_![imp $is | usize, usize:$is];
					impl_![imp $us | usize, $us:usize];
					impl_![imp isize | $is, $is:isize];
					impl_![imp isize | $us, $us:isize];
					impl_![imp usize | $is, usize:$is];
					impl_![imp usize | $us, $us:usize];
				)+
			};
			(gt ptr; $($is:ty:$us:ty),+) => {
				$(impl_![imp isize:usize, $is:$us];)+
			};
		}

		impl_![i8: u8, i16: u16, i32: u32, i64: u64, i128: u128];
		#[cfg(target_pointer_width = "32")]
		mod size_order_for_ptr {
			use super::SizeOrder;
			impl_![lt ptr; i8: u8, i16: u16];
			impl_![eq ptr; i32: u32];
			impl_![gt ptr; i64: u64, i128: u128];
		}

		#[cfg(target_pointer_width = "64")]
		mod size_order_for_ptr {
			use super::SizeOrder;
			impl_![lt ptr; i8: u8, i16: u16, i32: u32];
			impl_![eq ptr; i64: u64];
			impl_![gt ptr; i128: u128];
		}

		macro_rules! impl_ {
			($t0:ty, $t1:ty, $($ts:ty),+) => {
				impl_![imp $t0, $t1];
				impl_![$t1, $($ts),+];
			};

			($t0:ty, $t1:ty) => {
				impl_![imp $t0, $t1];
			};

			(imp $t0:ty, $t1:ty) => {
				impl IntoLarger for $t0 {
					type LargerType = $t1;
				}
			};
		}

		impl_![i8, i16, i32, i64, i128];
		impl_![u8, u16, u32, u64, u128];
	}
}

pub mod math {
	pub mod number {
		pub mod modint {
			use crate::traits::consts::Constant;
			use crate::traits::integer::{IntoLarger, SizeOrder};
			use num::traits::{AsPrimitive, One, Zero};
			use std::ops::{Add, Div, Mul, Sub};

			pub struct ModInt<M>
			where
				M: Constant,
			{
				value: M::Type,
			}

			impl<T, U, M> From<T> for ModInt<M>
			where
				M: Constant,
				M::Type: num::Integer + num::Signed + SizeOrder<T, LargerType = U> + AsPrimitive<U>,
				T: num::Integer + SizeOrder<M::Type, LargerType = U> + AsPrimitive<U>,
				U: num::Integer + AsPrimitive<M::Type>,
			{
				fn from(src: T) -> Self {
					debug_assert!(M::value() >= M::Type::zero());
					let src: U = src.as_();
					let modulus: U = M::value().as_();
					let value = num::integer::mod_floor(src, modulus).as_();
					Self { value }
				}
			}

			impl<M> std::fmt::Display for ModInt<M>
			where
				M: Constant,
				M::Type: std::fmt::Display,
			{
				fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
					write!(f, "{}", self.value)
				}
			}

			impl<M> std::fmt::Debug for ModInt<M>
			where
				M: Constant,
				M::Type: std::fmt::Debug,
			{
				fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
					f.debug_tuple("ModInt").field(&self.value).finish()
				}
			}

			impl<M> Clone for ModInt<M>
			where
				M: Constant,
				M::Type: Clone,
			{
				fn clone(&self) -> Self {
					Self {
						value: self.value.clone(),
					}
				}
			}

			impl<M> Copy for ModInt<M>
			where
				M: Constant,
				M::Type: Copy,
			{
			}

			impl<M> Default for ModInt<M>
			where
				M: Constant,
				M::Type: Default,
			{
				fn default() -> Self {
					Self {
						value: M::Type::default(),
					}
				}
			}

			macro_rules! impl_std_ops {
				($trait:ident:$fn:ident for $type:ty) => {
					impl_std_ops!($type; $trait:$fn);
					impl_std_ops!($type; $trait:$fn<'a, &>);
					impl_std_ops!($type; <'a, &> $trait:$fn);
					impl_std_ops!($type; <'a, &> $trait:$fn<'b, &>);
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Add:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Add<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: Copy + num::Integer,
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							let value = self.value.$fn(rhs.value);
							ModInt { value: if value >= M::value() { value - M::value() } else { value } }
						}
					}
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Sub:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Sub<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: Copy + num::Integer + num::Signed,
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							let value = self.value.$fn(rhs.value);
							ModInt { value: if value < M::Type::zero() { value + M::value() } else { value } }
						}
					}
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Mul:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Mul<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: num::Integer + IntoLarger + AsPrimitive<<M::Type as IntoLarger>::LargerType>,
						<M::Type as IntoLarger>::LargerType: num::Integer + AsPrimitive<M::Type>,
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							let modulus: <M::Type as IntoLarger>::LargerType = M::value().as_();
							let lhs: <M::Type as IntoLarger>::LargerType = self.value.as_();
							let rhs: <M::Type as IntoLarger>::LargerType = rhs.value.as_();
							let value: M::Type = num::integer::mod_floor(lhs.$fn(rhs), modulus).as_();
							ModInt { value }
						}
					}
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Div:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Div<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: Copy + num::Integer + num::Signed,
						$($ref_self$lt_self)?$type : Mul<$type, Output = $type>
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							self * rhs.inverse()
						}
					}
				};
			}

			impl_std_ops!(Add:add for ModInt<M>);
			impl_std_ops!(Sub:sub for ModInt<M>);
			impl_std_ops!(Mul:mul for ModInt<M>);
			impl_std_ops!(Div:div for ModInt<M>);

			impl<M> std::ops::Neg for ModInt<M>
			where
				M: Constant,
				M::Type: num::Integer + num::Signed,
			{
				type Output = Self;
				fn neg(self) -> Self::Output {
					Self {
						value: if self.value == M::Type::zero() {
							M::Type::zero()
						} else {
							M::value() - self.value
						},
					}
				}
			}

			impl<M> Zero for ModInt<M>
			where
				M: Constant,
				M::Type: num::Zero + num::Integer,
				Self: Add<Output = Self>,
			{
				fn zero() -> Self {
					Self {
						value: M::Type::zero(),
					}
				}

				fn is_zero(&self) -> bool {
					self.value == M::Type::zero()
				}
			}

			impl<M, U> num::traits::Pow<U> for ModInt<M>
			where
				M: Constant,
				Self: Copy + One,
				U: num::Integer + num::Unsigned,
			{
				type Output = Self;
				fn pow(self, rhs: U) -> Self {
					let mut r = Self::one();
					let mut b = rhs;
					let mut a = self;
					while b > U::zero() {
						if b.is_odd() {
							r = r * a;
						}
						a = a * a;
						b = b / (U::one() + U::one());
					}
					r
				}
			}

			impl<M> One for ModInt<M>
			where
				M: Constant,
				M::Type: num::Integer,
				Self: Mul<Output = Self>,
			{
				fn one() -> Self {
					Self {
						value: M::Type::one(),
					}
				}
			}

			impl<M> ModInt<M>
			where
				M: Constant,
			{
				pub fn value(&self) -> &M::Type {
					&self.value
				}
			}

			impl<M> ModInt<M>
			where
				M: Constant,
				M::Type: Copy + num::Integer + num::Signed,
			{
				pub fn inverse(self) -> Self {
					let mut r = (M::value(), self.value);
					let mut s = (M::Type::zero(), M::Type::one());
					while r.1 != M::Type::zero() {
						let q = r.0 / r.1;
						let nr = r.0 - q * r.1;
						r = (r.1, nr);
						let ns = s.0 - q * s.1;
						s = (s.1, ns);
					}
					if r.0 > M::Type::one() {
						panic!();
					}
					Self {
						value: if s.0 < M::Type::zero() {
							s.0 + M::value()
						} else {
							s.0
						},
					}
				}
			}

			#[macro_export]
			macro_rules! define_runtime_modint {
				($mint:ident; $modulus:ident with $mod:ident: $type:ty) => {
					type $mint = $crate::math::number::modint::ModInt<$modulus>;
					thread_local! { static $mod: std::cell::RefCell<$type> = std::cell::RefCell::new(0); }
					struct $modulus;
					impl $modulus {
						pub fn with<T, F: FnOnce() -> T>(modulus: $type, f: F) -> T {
							$mod.with(|m| {
								*m.borrow_mut() = modulus;
								let _m = m.borrow();
								f()
							})
						}
					}
					unsafe impl traits::marker::Unsafe for $modulus {}
					impl traits::consts::Constant for $modulus {
						type Type = $type;
						fn value() -> Self::Type {
							$mod.with(|m| *m.borrow())
						}
					}
				};
			}
		}
	}
}