数学作业 递推+矩阵快速幂
Solution:
设fi表示1~i构成的数除以M的余数,记x为i的位数。
不难写出递推式:
\[f_i=(f_{i-1}*10^x+i)\ mod\ M
\]
但是线性的递推显然会TLE,所以考虑优化。
注意到x最大只能到18,所以可以把转移过程分成18段,这样每一段的x都相等
那么就可以利用矩阵快速幂加速递推了。
若状态矩阵为:
\[\left[\begin{array}
{ccc}
f_i&i+1&1
\end{array}
\right]
\]
转移矩阵应为:
\[{
\left[\begin{array}
{ccc}
10^x & 0 & 0\\
1 & 1 & 0\\
0 & 1 & 1
\end{array}
\right]}
\]
Code:
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define int unsigned long long
#define DB double
using namespace std;
IL int gi() {
char ch=getchar(); RG int x=0,w=0;
while(ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
return w?-x:x;
}
int n,mod;
struct Matrix {
int MT[4][4];
Matrix() {memset(MT,0,sizeof(MT));}
IL void NewMT() {
RG int i;
for(i=0;i<=3;++i) MT[i][i]=1;
}
Matrix operator *(const Matrix &s) {
RG int i,j,k;
RG Matrix ans;
for(i=1;i<=3;++i)
for(j=1;j<=3;++j)
for(k=1;k<=3;++k)
(ans.MT[i][j]+=MT[i][k]*s.MT[k][j]%mod)%=mod;
return ans;
}
}f,g;
IL Matrix qpow(Matrix x,int p) {
RG Matrix ans;
ans.NewMT();
for(;p;p>>=1,x=x*x)
if(p&1) ans=ans*x;
return ans;
}
signed main()
{
RG int k,t,x,cnt=0;
x=n=gi(),mod=gi();
while(x) ++cnt,x/=10;
f.MT[1][2]=f.MT[1][3]=1;
g.MT[1][1]=g.MT[2][1]=g.MT[2][2]=g.MT[3][2]=g.MT[3][3]=1;
for(k=1,t=9;k<cnt;++k) {
g.MT[1][1]=g.MT[1][1]*10%mod;
f=f*qpow(g,t),t=t*10;
}
g.MT[1][1]=g.MT[1][1]*10%mod;
f=f*qpow(g,n-(int)pow(10,cnt-1)+1);
printf("%llu\n",f.MT[1][1]);
return 0;
}