bzoj2326: [HNOI2011]数学作业(矩阵乘法)

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\n",C.m[1][1]%m);
53     return 0;
54 }

 

posted @ 2018-03-27 15:59  CHerish_OI  阅读(178)  评论(0编辑  收藏  举报