bzoj 2326 矩阵乘法

[HNOI2011]数学作业

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2415  Solved: 1413
[Submit][Status][Discuss]

Description

 

思路:令f[n]表示Concatenate(1,n)。那么有:

f[i]=f[i-1]*10+(i-1)+1   1<=i<=9

f[i]=f[i-1]*100+(i-1)+1  10<=i<=99

……

因此可用矩阵加速:

但是,这个矩阵是分段的。

 

分段矩阵乘法即可。

 

 1 #include<cstring>
 2 #include<cmath>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cstdio>
 6 
 7 #define ll long long
 8 using namespace std;
 9 
10 ll n,m;
11 ll a[4][4],b[4][4];
12 
13 ll mul(ll a,ll b)
14 {
15     ll ans=0;
16     while(b)
17     {
18         if (b%2==1) ans=(ans+a)%m;
19         a=(a<<1)%m;
20         b>>=1;
21     }
22     return ans;
23 }
24 void mmul(ll a[4][4],ll b[4][4],ll c[4][4])
25 {
26     ll t[4][4];
27     for (int i=1;i<=3;i++)
28         for (int j=1;j<=3;j++)
29         {
30             t[i][j]=0;
31             for (int k=1;k<=3;k++)
32                 t[i][j]=(t[i][j]+mul(a[i][k],b[k][j]))%m;
33         }
34     for (int i=1;i<=3;i++)
35         for (int j=1;j<=3;j++)
36             c[i][j]=t[i][j];
37 }
38 void cal(ll t,ll x)
39 {
40     memset(b,0,sizeof(b));
41     b[1][1]=t,b[2][1]=b[2][2]=b[3][1]=b[3][2]=b[3][3]=1;
42     ll y=x-t/10+1;
43     while(y)
44     {
45         if (y&1) mmul(a,b,a);
46         mmul(b,b,b);
47         y>>=1;
48     }
49 }
50 int main()
51 {
52     scanf("%lld%lld",&n,&m);
53     for (int i=1;i<=3;i++)
54         a[i][i]=1;
55     ll t=10;
56     while(n>=t)
57     {
58         cal(t,t-1);
59         t*=10;
60     }
61     cal(t,n);
62     printf("%lld",a[3][1]);    
63 }

 

posted @ 2017-12-19 18:34  Kaiser-  阅读(179)  评论(0编辑  收藏  举报