题解 P3216 【[HNOI2011]数学作业】
40 pts
首先我们有fn=fn-1*10^k+i;
这样我们打个暴力得手
100 pts
我们考虑优化,即发现其实k的变化最多18以内
所以我们考虑对于不同的k分段考虑
对于每个k既可以得到一个矩阵
我们考虑如何建立这个矩阵
于是我们思考这个矩阵是
[ f[i] i + 1 1] 乘 一个3乘3的矩阵
得到[ f[i + 1] i + 2 1]
我们可以推出矩阵为
[ 10 ^ k 0 0]
[ 1 1 0]
[0 1 1]
所以分段考虑矩阵乘法
同时建立一个初始矩阵即可
放上我的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct mat {
ll a[3][3];
} c, ans;
ll n, m, tmp, t[20];
mat operator *(mat a, mat b) {
mat c;
int i, j, k;
for (i = 0; i < 3; ++i)
for (j = 0; j < 3; ++j) c.a[i][j] = 0;
for (i = 0; i < 3; ++i)
for (j = 0; j < 3; ++j)
for (k = 0; k < 3; ++k) c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j]) % m;
return c;
}
mat pw(mat x, ll y) {
if (y == 1) return x;
mat z = pw(x, y / 2);
z = z * z;
if (y & 1) z = z * x;
return z;
}
int main() {
int i;
scanf("%lld%lld", &n, &m);
ans.a[0][1] = ans.a[0][2] = c.a[1][0] = c.a[1][1] = c.a[2][1] = c.a[2][2] = 1;
for (t[0] = i = 1; i <= 18; ++i) t[i] = t[i - 1] * 10;
for (i = 1;; ++i) {
c.a[0][0] = t[i] % m;
tmp = min(n, t[i] - 1) - t[i - 1] + 1;
ans = ans * pw(c, tmp);
if (t[i] - 1 >= n) break;
}
printf("%lld\n", ans.a[0][0]);
return 0;
}