2326: [HNOI2011]数学作业
题目:传送门
题解:
做的矩阵乘法太少了...被lxj大佬一眼秒...
不难得到递推柿子:f[n]=f[n-1]*10^k+n
那么因为10^k是分段固定的,所以分开不同的位数进行矩阵乘法其实就ok
{ 10^k, 1, 1 } { f[n-1] } { f[n] }
{ 0, 1, 1 } X { n-1 } = { n }
{ 0, 0, 1 } { 1 } { 1 }
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 typedef long long LL; 8 struct matrix 9 { 10 LL m[5][5]; 11 matrix(){memset(m,0,sizeof(m));} 12 }A,B,C,pre; 13 LL n,m,T,k; 14 matrix multi(matrix a,matrix b) 15 { 16 matrix c; 17 for(int i=1;i<=3;i++) 18 for(int j=1;j<=3;j++) 19 for(int k=1;k<=3;k++) 20 c.m[i][j]=(c.m[i][j]+(a.m[i][k]*b.m[k][j])%m)%m; 21 return c; 22 } 23 matrix sol(LL t,LL s) 24 { 25 matrix ans; 26 for(int i=1;i<=3;i++)ans.m[i][i]=1; 27 pre.m[1][1]=t%m; 28 pre.m[1][2]=pre.m[1][3]=pre.m[2][2]=pre.m[2][3]=pre.m[3][3]=1; 29 while(s) 30 { 31 if(s%2==1)ans=multi(ans,pre); 32 pre=multi(pre,pre); 33 s/=2; 34 } 35 return ans; 36 } 37 int main() 38 { 39 //freopen("2326.in","r",stdin); 40 //freopen("ans.out","w",stdout); 41 scanf("%lld%lld",&n,&m); 42 C.m[3][1]=1; 43 T=n,k=0;while(T)T/=10,k++;LL la=1,s;T=1; 44 for(int i=1;i<=k;i++) 45 { 46 if(i!=1)la*=10;T*=10; 47 if(T>n)s=n-(T/10)+1; 48 else s=la*9; 49 A=sol(T,s); 50 C=multi(A,C); 51 } 52 printf("%lld ",C.m[1][1]%m); 53 return 0; 54 }