裸的矩阵快速幂。
设\(S_i\)表示\(Concatenate(1...i)\)的值,\(f(i)\)为数字\(i\)的位数,得到递推式\(S_i=S_{i-1}*10^i+i\)
设状态矩阵为
\[
\begin{bmatrix}
S_{i-1}\quad i \quad 1
\end{bmatrix}
\]
其中\(1\)是为了方便\(i\)加\(1\)
转移矩阵为
\[
\begin {bmatrix}
10^{f(i)} \quad 0 \quad 0\ 1 \qquad 1 \qquad 0 \ 0 \qquad 1 \qquad 1 \\end {bmatrix}
\]
我们发现,这个\(f(i)\)会变化,无法进行矩阵快速幂。然而\(N≤10^{18}\)也就是说\(f(i)\)最多会变化\(18\)次,接下来只需要暴力分段枚举\(10^{f(i)}\)就可以了。
#include <cstdio>
#include <cstring>
typedef long long ll;
struct Matrix
{
ll matrix[3][3];
Matrix()
{
memset(matrix,0,sizeof(matrix));
}
void clear()
{
memset(matrix,0,sizeof(matrix));
}
}S,T;
ll N,M;
Matrix mul(Matrix x,Matrix y)
{
Matrix s;
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
for(int k=0;k<3;++k)
(s.matrix[i][j]+=(x.matrix[i][k]*y.matrix[k][j])%M)%=M;
return s;
}
Matrix fst_pow(Matrix a,ll x)
{
Matrix r=a,base=a;
for(x=x-1;x;x>>=1)
{
if(x&1) r=mul(r,base);
base=mul(base,base);
}
return r;
}
int main()
{
ll t,x;
scanf("%lld %lld",&N,&M);
t=N;
S.matrix[0][1]=S.matrix[0][2]=1;
for(ll i=10;t;i*=10)
{
if(N>=i) x=i-i/10;
else x=t;
t-=x;
T.clear();
T.matrix[1][0]=T.matrix[1][1]=T.matrix[2][1]=T.matrix[2][2]=1,T.matrix[0][0]=i%M;
S=mul(S,fst_pow(T,x));
}
printf("%lld",S.matrix[0][0]);
return 0;
}