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