测试地址:数学作业
做法:本题需要用到递推+矩阵快速幂。
令f(i)f(i)为Concatenate(i)Concatenate(i)对mm取模后的结果,很快能得到一个递推式:
f(i+1)=f(i)×10k+i+1f(i+1)=f(i)×10k+i+1
注意到所需的信息:f(i)f(i)和i+1i+1,它们是可以同时递推的,所以我们就可以构造一个转移矩阵,使得能从向量{f(i),i+1,1}{f(i),i+1,1}转移到{f(i+1),i+2,1}{f(i+1),i+2,1},应该很容易构造,实在不会请看代码。而kk的话最大也就1919,因此我们只需对于k=1,2,...k=1,2,...的每段都求一遍矩阵快速幂即可,时间复杂度为O(log2n)O(log2n)。
以下是本人代码:
#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;
}