bzoj(矩阵快速幂)

时间:2023-03-09 05:11:26
bzoj(矩阵快速幂)

题意:定义Concatenate(1,N)=1234567……n。比如Concatenate(1,13)=12345678910111213。给定n和m,求Concatenate(1,n)%m。 (1=<n<=10^18,1<=m<=10^9)

思路:令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

……

因此可用矩阵加速:

bzoj(矩阵快速幂)

这样按位数分段来矩阵快速幂1~9,10~99,100~999......这里构造矩阵要注意细节;设上面两个矩阵分别为F,G;则要从F0开始;

这样刚好Fn=G^n*F0;如果是G^(n-1)*F1=Fn的话,在分段过程中会出错的(原因自己尽量想想)。

而F0={0,0,1},所以Fn=0*Gn.m[0][0]+0*Gn.m[0][1]+1*Gn.m[2][0]=Gn.m[2][0].

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define inf 1<<30
#define N 100010
using namespace std;
struct matrix
{
LL m[][];
}ans;
LL dig[],n,mod;
matrix mult(matrix a,matrix b)
{
matrix c;
memset(c.m,,sizeof(c.m));
for(int i=;i<;i++)
for(int k=;k<;k++)
{
if(a.m[i][k]==)continue;
for(int j=;j<;j++)
{
if(b.m[k][j]==)continue;
c.m[i][j]+=a.m[i][k]*b.m[k][j]%mod;
c.m[i][j]%=mod;
}
}
return c;
}
matrix quickmod(matrix a,LL n)
{
matrix temp;
memset(temp.m,,sizeof(temp.m));
for(int i=;i<;i++)temp.m[i][i]=;
while(n)
{
if(n&)temp=mult(temp,a);
a=mult(a,a);
n>>=;
}
return temp;
}
matrix solve(LL n,LL t)
{
matrix x;
x.m[][]=t%mod;x.m[][]=;x.m[][]=;
x.m[][]=;x.m[][]=;x.m[][]=;
x.m[][]=;x.m[][]=;x.m[][]=;
return quickmod(x,n);
} int main()
{
dig[]=;
for(int i=;i<=;i++)dig[i]=dig[i-]*;
while(scanf("%lld%lld",&n,&mod)!=EOF)
{
memset(ans.m,,sizeof(ans.m));
for(int i=;i<;i++)
ans.m[i][i]=;
for(int i=;;i++)
{
LL left=dig[i-];
LL right=min(n,dig[i]-);
ans=mult(ans,solve(right-left+,dig[i]));
if(right==n)break;
}
printf("%lld\n",ans.m[][]);
}
}