题面:传送门
设 fx f x 为 123...101112...100101102...x 123...101112...100101102... x 对 m m 取模的答案,则最终答案为。很容易得到递推式:
由于 ⌊lg x⌋+1 ⌊ l g x ⌋ + 1 的不同的取值数量不超过19个,所以我们考虑分块矩乘。
得出矩阵递推式:
用快速幂优化,然后就做完了。
时间复杂度: Θ(32⋅log2n⋅lg n) Θ ( 3 2 · l o g 2 n · l g n ) 。
我的代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
long long n;
int m;
struct mat{
int a[4][4];
mat(){memset(a,0,sizeof(a));}
mat operator*(mat u)const
{
mat res;
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
for(int k=1;k<=3;k++)
{
res.a[i][j]+=1LL*a[i][k]*u.a[k][j]%m;
if(res.a[i][j]>=m)res.a[i][j]-=m;
}
}
}
return res;
}
};
mat un;
mat t;
mat ans;
mat qmul(mat x,long long p)
{
if(p==0)return un;
if(p==1)return x;
mat res=qmul(x,p>>1LL);
res=res*res;
if(p&1LL)res=res*x;
return res;
}
int main()
{
un.a[1][1]=un.a[2][2]=un.a[3][3]=1;
t.a[1][2]=t.a[1][3]=t.a[2][2]=t.a[2][3]=t.a[3][3]=1;
ans.a[1][1]=0;
ans.a[2][1]=0;
ans.a[3][1]=1;
scanf("%lld%d",&n,&m);
long long cur=10LL;
while(n>=cur)
{
t.a[1][1]=cur%m;
ans=qmul(t,cur/10LL*9LL)*ans;
cur*=10LL;
}
t.a[1][1]=cur%m;
ans=qmul(t,n+1-cur/10LL)*ans;
printf("%d",ans.a[1][1]);
return 0;
}