http://www.lydsy.com/JudgeOnline/problem.php?id=2326
递推:f[i]= f[i-1]*(10^log(i))+i mod M
构造矩阵:
{f[i-1] i-1 1} {10^log(i) 0 0 } { f[i] i 1}
* {1 1 0 }
{ 0 1 1 }
也是:
| 10^log(i) 1 1 | {f[i-1]} {f[i]}
| 0 1 1 | { i-1} { i }
| 0 0 1 | { 1} {1}
然后,初始化一下,对于每个数位做一次矩阵乘法,把结果乘起来。
(结果不会爆long long ,没有必要用乘法优化)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=5;
ll n,m;
struct Mat
{
ll mat[maxn][maxn];
Mat()
{
memset(mat,0,sizeof(mat));
}
Mat operator *(const Mat &b)
{
Mat c;
for(int k=1;k<=3;k++)
{
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
c.mat[i][j]+=mat[i][k]*b.mat[k][j];
c.mat[i][j]%=m;
}
}
}
return c;
}
};
//f[i]= f[i-1]*(10^log(i))+i mod M
/*
f[i-1] i-1 1 10^log(i) 0 0 f[i] i 1
1 1 0
0 1 1
10^log(i) 1 1 f[i-1]
0 1 1 i-1
0 0 1 1
*/
Mat ans;
Mat cal(ll k,ll t)
{
Mat res;
Mat b;
ll y=t-k/10+1;
b.mat[1][1]=k%m;
b.mat[1][2]=b.mat[2][2]=b.mat[2][3]=b.mat[3][3]=b.mat[1][3]=1;
for(int i=1;i<=3;i++)res.mat[i][i]=1;
while(y)
{
if(y&1)res=res*b;
y>>=1;
b=b*b;
}
return res;
}
int main()
{
//for(int i=1;i<=3;i++)ans.mat[i][i]=1;
ans.mat[3][1]=1;
scanf("%lld%lld",&n,&m);
ll t=10;
for(int i=1;i<=18;i++)
{
ans=cal(t,t-1)*ans;
t*=10;
if(t>n)break;
}
ans=cal(t,n)*ans;
printf("%lld\n",ans.mat[1][1]);
return 0;
}