【HNOI2011】数学作业 题解(递推+矩阵快速幂)
题目大意:求$1-n$所拼接起来的数$mod\ m$的值。
-----------------------------------
递推式子很好想:$f_i=f_{i-1}*10^{\lg i+1}+i$
看到数据范围,肯定不能$O(n)$递推。考虑矩阵加速。
转移矩阵为:
$\begin{pmatrix}10^k&0&0\\1&1&0\\1&1&1\end{pmatrix}$
因为$10^k$是不确定的,所以我们要根据范围来分情况作乘法。详见代码。
PS:这个题我调了好久……要注意幂的大小和矩阵初始化。
代码:
#include<bits/stdc++.h> #define int long long using namespace std; int n,mod,cnt; struct node { int a[4][4]; node(){ memset(a,0,sizeof(a)); } inline void build(){ for (int i=1;i<=3;i++) a[i][i]=1; } }ans; node operator *(const node x,const node y) { node z; for (int k=1;k<=3;k++) for (int i=1;i<=3;i++) for (int j=1;j<=3;j++) z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j])%mod; return z; } inline int qcal(int x,int y) { int res=1; while(y){ if (y&1) res=res*x%mod; x=x*x%mod; y>>=1; } return res%mod; } signed main() { cin>>n>>mod; ans.build(); for (int i=1;;i*=10) { cnt++;int mi; node a;a.a[1][1]=qcal(10,cnt); a.a[2][1]=a.a[2][2]=a.a[3][1]=a.a[3][2]=a.a[3][3]=1; if (n<i*10) { mi=n-i+1; while(mi) { if (mi&1) ans=ans*a; a=a*a; mi>>=1; } int sum=ans.a[3][1]; printf("%lld",sum%mod); return 0; } mi=i*9; while(mi) { if (mi&1) ans=ans*a; a=a*a; mi>>=1; } } return 0; }