数学作业
Description
突然发现矩阵乘法写得不熟……
(本zz重载运算符不打return调试整整30min)
发现一个很简单的递推式:
f[n]=f[n−1]∗(floor(lg10)+1)+n
那么发现这个
floor(lg10)+1
显然会有很长一段相同,所以这个值可以分块。
那么考虑按
floor(lg10)
的值分块,形如10..999,100…999,相同的无需重复计算。
考虑使用矩阵乘法优化这个过程:
令
floor(lg10)+1=x
那么对于每一块可以构造如下转移矩阵:
x 0 0
1 1 0
0 1 1
直接分块矩阵快速幂即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5;
ll n,md;
struct matrix
{
ll a[N][N],lena,lenb;
void e()
{
for(int i=0;i<lena;i++)
a[i][i]=1;
}
matrix(int _a,int _b,ll f=-1)
{
lena=_a;
lenb=_b;
memset(a,0,sizeof(a));
if(f!=-1)
{
e();
a[0][0]=f;
a[1][0]=a[2][1]=1;
}
}
matrix operator * (matrix o)
{
matrix res(lena,o.lenb);
for(int i=0;i<lena;i++)
for(int j=0;j<o.lenb;j++)
for(int k=0;k<lenb;k++)
(res.a[i][j]+=a[i][k]*o.a[k][j]%md)%=md;
return res;
}
void out()
{
for(int i=0;i<lena;i++,puts(""))
for(int j=0;j<lenb;j++)
printf("%lld ",a[i][j]);
}
};
inline matrix qpow(matrix a,ll b)
{
matrix ret(3,3);
ret.e();
while(b)
{
if(b&1)
ret=ret*a;
a=a*a;
b>>=1;
}
return ret;
}
int main()
{
scanf("%lld%lld",&n,&md);
matrix ans(3,3);
ans.e();
ll i;
for(i=10;i<=n;i=i*10)
ans=ans*qpow(matrix(3,3,i%md),i-i/10);
ans=ans*qpow(matrix(3,3,i%md),n-i/10+1);
printf("%lld\n",(ans.a[1][0]+ans.a[2][0])%md);
return 0;
}