bzoj 2326 矩阵乘法
[HNOI2011]数学作业
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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 }