【Luogu P3216】[HNOI2011]数学作业
链接:
题目大意:
求:
\[\text{Concatenate}(n) \bmod \ m
\]
其中 \(\text{Concatenate}(n)\) 表示将 \(1 \sim n\) 所有正整数顺序连接在一起得到的数。
正文:
可以把题目转化为递推的形式:
\[\begin{aligned}f(1)&=1\\
f(n)&=\left(10^{\left\lfloor\log_{10} n\right\rfloor+1}f(n-1)+n\right)\bmod \ m\end{aligned}\]
时间复杂度 \(\mathcal{O}(n)\) 不能接受,考虑用矩阵优化:
\[\begin{bmatrix}f(n)\\n\\1\end{bmatrix}=\begin{bmatrix}10^{\left\lfloor\log_{10} n\right\rfloor+1}&1&1\\0&1&1\\0&0&1\end{bmatrix}\cdot\begin{bmatrix}f(n-1)\\n-1\\1\end{bmatrix}
\]
因为 \(\left\lfloor\log_{10} n\right\rfloor+1\) 随时可能变化,就对于每个单独处理,因为 \(n\leq10^{18}\),所以最多循环 \(18\) 次。
总时间复杂度 \(\mathcal{O}(\log n)\)。
代码:
const int N = 110;
int f[N];
ll n, mod;
struct matrix
{
ll mat[N][N];
int n, m;
matrix(int _n, int _m)
{
n = _n, m = _m;
memset(mat, 0, sizeof mat);
}
inline ll* operator [] (int b) { return mat[b];}
}F(3, 1);
inline matrix operator*(matrix a, matrix b)
{
matrix c(a.n, b.m);
for (int i = 1; i <= a.n; i++)
for (int j = 1; j <= b.m; j++)
for (int k = 1; k <= a.m; k++)
c[i][j] = (c[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
return c;
}
matrix qpow(matrix a, ll b)
{
matrix ans(a.n, a.m);
for (int i = 1; i <= ans.n; i++)
ans[i][i] = 1;
for (; b; b >>= 1)
{
if(b & 1) ans = ans * a;
a = a * a;
}
return ans;
}
void Solve (ll k, ll b)
{
matrix base(3, 3);
base[1][1] = k % mod,
base[1][2] = base[1][3] = base[2][2] = base[2][3] = base[3][3] = 1;
F = qpow(base, b) * F;
}
int main()
{
scanf ("%lld%lld", &n, &mod);
ll r = 10;
F[3][1] = 1;
for (; r <= n; r *= 10)
Solve (r, r - (r / 10));
Solve (r, n - (r / 10) + 1);
printf ("%lld\n", F[1][1]);
return 0;
}