矩阵乘法神题
我一开始写了个这样的暴力,骗了40分
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
lli n,mod,m;
signed main()
{
cin>>n>>mod;
for (int i=1;i<=min(1LL*9,n);i++) m=(m*10+i)%mod;
for (int i=10;i<=min(1LL*99,n);i++) m=(m*100+i)%mod;
for (int i=100;i<=min(1LL*999,n);i++) m=(m*1000+i)%mod;
for (int i=1000;i<=min(1LL*9999,n);i++) m=(m*10000+i)%mod;
for (int i=10000;i<=min(1LL*99999,n);i++) m=(m*100000+i)%mod;
for (int i=100000;i<=min(1LL*999999,n);i++) m=(m*1000000+i)%mod;
for (int i=1000000;i<=min(1LL*9999999,n);i++) m=(m*10000000+i)%mod;
for (int i=10000000;i<=min(1LL*99999999,n);i++) m=(m*100000000+i)%mod;
cout<<m;
return 0;
}
然后发现这个玩意在一定的区间内,是可以递推的n-1->n,先*10^若干然后+n,之后就卡住了,看了一波题解,发现矩乘可以分段矩乘,有道理诶,最多乘18次,就是把n划分成上面那样的区间处理,然后就木了
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
lli n,mod;
struct mtix
{
lli a[5][5];
mtix(){memset(a,0,sizeof(a));}
}f,g;
mtix mul(mtix x,mtix y)
{
mtix z;
for (int i=1;i<=3;i++)
for (int j=1;j<=3;j++)
for (int k=1;k<=3;k++)
z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
return z;
}
mtix mpow(lli x,lli y)
{
mtix ans,e;lli k=y-x/10+1;
e.a[1][1]=x%mod;
e.a[1][2]=e.a[1][3]=e.a[2][3]=e.a[2][2]=e.a[3][3]=1;
for (int i=1;i<=3;i++) ans.a[i][i]=1;
for (;k;e=mul(e,e),k>>=1)
if (k&1) ans=mul(ans,e);
return ans;
}
signed main()
{
f.a[3][1]=1;cin>>n>>mod;lli t=10;
for (int i=1;i<=18;i++)
{
g=mpow(t,t-1);f=mul(g,f);
t*=10;if (t>n) break;
}
g=mpow(t,n);f=mul(g,f);
cout<<f.a[1][1];
return 0;
}