2326: [HNOI2011]数学作业
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2249 Solved: 1301
[ Submit][ Status][ Discuss]
Description
令F(n) = Concatenate(1, n)
那么有
F(x) = F(x-1)*10+(x-1)+1 x∈(1, 9)
F(x) = F(x-1)*100+(x-1)+1 x∈(10, 99)
F(x) = F(x-1)*1000+(x-1)+1 x∈(100, 999)
F(x) = F(x-1)*10000+(x-1)+1 x∈(1000, 9990)
……
其中最多18段(题目中没有n=10^18这组数据)
每一段的公式都可以转成对应的矩阵快速幂
这样复杂度就是O(logn)了
矩阵方程:
#include<stdio.h>
#include<string.h>
#define LL long long
typedef struct
{
LL a[4][4];
void init(LL x)
{
memset(a, 0, sizeof(a));
a[1][1] = x;
a[2][1] = a[2][2] = a[3][1] = a[3][2] = a[3][3] = 1;
}
void unit()
{
memset(a, 0, sizeof(a));
a[1][1] = a[2][2] = a[3][3] = 1;
}
}Matrix;
Matrix Jz;
LL ans[4], temp[4];
Matrix Mult(Matrix A, Matrix B, LL mod)
{
LL i, j, k;
Matrix C;
memset(C.a, 0, sizeof(C.a));
for(i=1;i<=3;i++)
{
for(j=1;j<=3;j++)
{
for(k=1;k<=3;k++)
C.a[i][j] = (C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
}
}
return C;
}
Matrix Pow(Matrix A, LL b, LL mod)
{
Matrix C;
C.unit();
while(b)
{
if(b%2)
C = Mult(C, A, mod);
A = Mult(A, A, mod);
b /= 2;
}
return C;
}
int main(void)
{
LL n, m, i, j, k, flag;
while(scanf("%lld%lld", &n, &m)!=EOF)
{
ans[1] = ans[2] = 0;
ans[3] = 1;
flag = 0;
if(n==(LL)1e18-1)
flag = 1, n--;
for(i=9;i<=n&&i>=9;i=i*10+9)
{
Jz.init((i+1)%m);
Jz = Pow(Jz, (i+1)/10*9, m);
temp[1] = ans[1], temp[2] = ans[2], temp[3] = ans[3];
ans[1] = ans[2] = ans[3] = 0;
for(j=1;j<=3;j++)
{
for(k=1;k<=3;k++)
ans[j] = (ans[j]+temp[k]*Jz.a[k][j])%m;
}
}
Jz.init((i+1)%m);
Jz = Pow(Jz, n-(i-9)/10, m);
temp[1] = ans[1], temp[2] = ans[2], temp[3] = ans[3];
ans[1] = ans[2] = ans[3] = 0;
for(j=1;j<=3;j++)
{
for(k=1;k<=3;k++)
ans[j] = (ans[j]+temp[k]*Jz.a[k][j])%m;
}
if(flag==1)
ans[1] = (ans[1]*((LL)1e18%m)+((LL)1e18-1)%m)%m;
printf("%lld\n", ans[1]%m);
}
return 0;
}