BZOJ-2326 数学作业 矩阵乘法快速幂+快速乘

时间:2021-06-05 07:11:31

2326: [HNOI2011]数学作业

Time Limit: 10 Sec Memory Limit: 128 MB

Submit: 1564 Solved: 910

[Submit][Status][Discuss]

Description

BZOJ-2326   数学作业    矩阵乘法快速幂+快速乘

Input

Output

Sample Input

Sample Output

HINT

Source

题解:

矩乘快速幂,构造矩阵:

BZOJ-2326   数学作业    矩阵乘法快速幂+快速乘

其中k为位数,所以分段进行快速幂;

1~9;10~99;100~999;….

开始4A6W,然后加了快速乘AC了,但是YveH做的比我慢一些,没用快速乘也A了。。可能姿势不对?

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
long long n,m;
long long A[4][4],B[4][4]; long long quick_mul(long long x,long long y,long long p)
{
if (y==0) return 0;
if (y==1) return x%p;
long long re;
re=quick_mul(x,y>>1,p);
if ((y&1)==1) return (re+re+x)%p;
else return (re+re)%p;
} void quick_pow(long long a[4][4],long long b[4][4],long long S[4][4])
{
long long tmp[4][4];
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
{
tmp[i][j]=0;
for(int k=1;k<=3;k++)
tmp[i][j]=(tmp[i][j]+quick_mul(a[i][k],b[k][j],m))%m;
}
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
S[i][j]=tmp[i][j];
}
void work(long long t,long long end)
{
B[1][1]=t;
B[2][1]=B[2][2]=B[3][1]=B[3][2]=B[3][3]=1;
B[1][2]=B[1][3]=B[2][3]=0;
long long y=end-t/10+1;
while(y)
{
if(y&1) quick_pow(A,B,A);
quick_pow(B,B,B);
y>>=1;
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=3;i++) A[i][i]=1;
long long t=10;
while(n>=t) work(t,t-1),t*=10;
work(t,n);
printf("%lld",A[3][1]);
return 0;
}