BZOJ 2326 数学作业
题意:
给出一个数字N(1e18),求1 ~ N 的数字排起来mod上M(<= 1e9)的值。
题解:
0.定义f[x]表示以数字x结尾的数字mod 上 M 的值。
1.
f[x] = f[x-1] * 10 + x - 1 + 1 x为个位数的情况
f[x] = f[x-1] * 100 + x - 1 + 1 x为两位数的情况
f[x] = f[x-1] * 1000 + x - 1 + 1 x为三位数的情况
......
2.这样就可以对不同位数的数建立矩阵进行加速转移
/************************************************************** Problem: 2326 User: xgtao Language: C++ Result: Accepted Time:24 ms Memory:1288 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define ll long long ll mod, n, pow[25]; struct Matrix { ll map[3][3]; void clear () { memset (map, 0, sizeof (map));} }; Matrix MatrixMul (Matrix x, Matrix y) { Matrix ret; ret.clear(); for (int i = 0; i < 3; ++i) for (int j = 0;j < 3; ++j) for (int k = 0; k < 3; ++k) ret.map[i][j] = (ret.map[i][j] + x.map[i][k] * y.map[k][j] % mod) % mod; return ret; } Matrix MatrixPow (Matrix x, ll n) { Matrix ret; ret.clear(); ret.map[0][0] = ret.map[1][1] = ret.map[2][2] = 1; while (n) { if (n & 1) ret = MatrixMul(ret, x); x = MatrixMul(x, x); n >>= 1; } return ret; } Matrix calc (ll x, ll n) { Matrix ret; ret.clear(); ret.map[0][0] = x % mod; ret.map[0][1] = 0; ret.map[0][2] = 0; ret.map[1][0] = 1; ret.map[1][1] = 1; ret.map[1][2] = 0; ret.map[2][0] = 1; ret.map[2][1] = 1; ret.map[2][2] = 1; return MatrixPow(ret, n); } int main () { pow[0] = 1; for (int i = 1; i <= 18; ++i) pow[i] = pow[i - 1] * 10; cin >> n >> mod; int cur = 1; Matrix ans; ans.clear(); ans.map[0][0] = ans.map[1][1] = ans.map[2][2] = 1; while (true) { ll L = pow[cur - 1], R = min (n, pow[cur] - 1); ans = MatrixMul (ans, calc(pow[cur], R - L + 1)); ++cur; if (R == n) break; } cout << ans.map[2][0] << endl; return 0; }