测试地址:数学作业
做法:本题需要用到递推+矩阵快速幂。
令
f(i)
f
(
i
)
为
Concatenate(i)
C
o
n
c
a
t
e
n
a
t
e
(
i
)
对
m
m
取模后的结果,很快能得到一个递推式:
注意到所需的信息:
f(i)
f
(
i
)
和
i+1
i
+
1
,它们是可以同时递推的,所以我们就可以构造一个转移矩阵,使得能从向量
{f(i),i+1,1}
{
f
(
i
)
,
i
+
1
,
1
}
转移到
{f(i+1),i+2,1}
{
f
(
i
+
1
)
,
i
+
2
,
1
}
,应该很容易构造,实在不会请看代码。而
k
k
的话最大也就,因此我们只需对于
k=1,2,...
k
=
1
,
2
,
.
.
.
的每段都求一遍矩阵快速幂即可,时间复杂度为
O(log2n)
O
(
log
2
n
)
。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll n,mod;
struct matrix
{
ll mat[3][3];
}M[110],S;
void mult(matrix &S,matrix A,matrix B)
{
memset(S.mat,0,sizeof(S.mat));
for(int i=0;i<=2;i++)
for(int j=0;j<=2;j++)
for(int k=0;k<=2;k++)
S.mat[i][j]=(S.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod;
}
void power(matrix &S,ll p)
{
int i=0;
while(p)
{
if (p&1) mult(S,M[i],S);
i++;p>>=1;
}
}
int main()
{
scanf("%llu%llu",&n,&mod);
ll now=0,limit=10;
memset(S.mat,0,sizeof(S.mat));
S.mat[0][0]=S.mat[1][1]=S.mat[2][2]=1;
while(now<n)
{
ll p;
if (limit<=n) p=limit-1-now;
else p=n-now;
M[0].mat[0][0]=limit%mod,M[0].mat[0][1]=1,M[0].mat[0][2]=0;
M[0].mat[1][0]=0,M[0].mat[1][1]=1,M[0].mat[1][2]=1;
M[0].mat[2][0]=0,M[0].mat[2][1]=0,M[0].mat[2][2]=1;
for(int i=1;i<=70;i++)
mult(M[i],M[i-1],M[i-1]);
power(S,p);
now=limit-1;
limit*=10;
}
printf("%llu",(S.mat[0][1]+S.mat[0][2])%mod);
return 0;
}