bzoj2326 [HNOI2011]数学作业
分析:设f[i]为1~i组成的数,可以得到f[i] = f[i-1] * 10^k + i.对于一个序列求第n项,一般可以用矩阵乘法来加速,但是每一个矩阵只能对应一个不变的递推式,这个式子中的k会变,那怎么办呢?那么在1~9,10~99,100~999每一次构造一个矩阵就好了,具体的矩阵如下:
f(i + 1) f(i) 10^k,1,1
i = i - 1 * 0, 1, 1
1 1 0, 0, 1
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> #include <cmath> using namespace std; long long n, m,i,ans[10][10],temp[10][10],t[10][10]; void mul1() { memset(t, 0, sizeof(t)); for (int i = 1; i <= 3; i++) for (int j = 1; j <= 3; j++) for (int k = 1; k <= 3; k++) { t[i][j] += ans[i][k] * temp[k][j]; t[i][j] %= m; } memcpy(ans, t, sizeof(ans)); } void mul2() { memset(t, 0, sizeof(t)); for (int i = 1; i <= 3; i++) for (int j = 1; j <= 3; j++) for (int k = 1; k <= 3; k++) { t[i][j] += temp[i][k] * temp[k][j]; t[i][j] %= m; } memcpy(temp, t, sizeof(temp)); } void qpow(long long b) { while (b){ if (b & 1) mul1(); b >>= 1; mul2(); } } int main() { scanf("%lld%lld", &n, &m); ans[1][3] = 1; for (i = 1; i <= (n + 1) / 10; i *= 10) { memset(temp, 0, sizeof(temp)); ans[1][2] = i % m; temp[1][1] = (i * 10) % m; temp[2][1] = temp[2][2] = temp[3][2] = temp[3][3] = 1; qpow(i * 9); } if (i <= n) { memset(temp, 0, sizeof(temp)); ans[1][2] = i % m; temp[1][1] = i * 10 % m; temp[2][1] = temp[2][2] = temp[3][2] = temp[3][3] = 1; qpow(n - i + 1); } printf("%lld\n", ans[1][1]); return 0; }