BZOJ2326 HNOI2011 数学作业 矩阵乘法
题意:求12345……101112……(N-1)N mod M的值(被模数就是1-N顺次连接起来)。
题解:丧病的数学老师,看自己写的题解都看不懂了QAQ,首先设${f_i}$=前i个数连接起来 mod M的值,然后按位数不断转移,也就是说,假定当前要增加的数i最高位是10^k,那么\[{f_i} = ({10^{k + 1}}{f_{i - 1}} + i)\bmod M\]
所以\[\left( {\begin{array}{*{20}{c}}
{{f_{{{10}^{k + 1}} - 1}}}&{{{10}^{k + 1}} - 1}&1
\end{array}} \right) = \left( {\begin{array}{*{20}{c}}
{{f_i}}&{{{10}^{k - 1}}}&1
\end{array}} \right){\left( {\begin{array}{*{20}{c}}
{{{10}^k}}&0&0\\
1&1&0\\
1&1&1
\end{array}} \right)^{{{10}^k} - 2}}\]
#include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #include <iostream> #include <algorithm> using namespace std; #define ll long long const int MAXN=4+2; ll N,M,a[MAXN][MAXN],b[MAXN][MAXN]; ll Quick_Mul(ll a,ll b){ a%=M,b%=M; ll t=(b&1?a:0); while(b>>=1){ a=(a+a)%M; if(b&1) t=(t+a)%M; } return t; } void Matrix_Mul(bool f){ ll t[MAXN][MAXN]; memset(t,0,sizeof(t)); if(!f){ for(int i=1;i<=3;i++) for(int j=1;j<=3;j++){ for(int k=1;k<=3;k++) t[i][j]=(t[i][j]+Quick_Mul(a[i][k],b[k][j]))%M; } memcpy(a,t,sizeof(a)); } else{ for(int i=1;i<=3;i++) for(int j=1;j<=3;j++){ for(int k=1;k<=3;k++) t[i][j]=(t[i][j]+Quick_Mul(b[i][k],b[k][j]))%M; } memcpy(b,t,sizeof(b)); } } void Quick_Pow(ll x,ll y){ memset(b,0,sizeof(b)); b[1][1]=x,b[2][1]=b[2][2]=b[3][1]=b[3][2]=b[3][3]=1; ll t=y-x/10+1; while(t){ if(t&1) Matrix_Mul(0); Matrix_Mul(1); t>>=1; } } int main(){ scanf("%lld %lld",&N,&M); a[1][1]=a[2][2]=a[3][3]=1; ll t=10; while(N>=t) Quick_Pow(t,t-1),t*=10; Quick_Pow(t,N); printf("%lld",a[3][1]); return 0; }