# [BZOJ2326] [HNOI2011] 数学作业 (矩阵乘法)

## Solution

递推式长这样：$f[n]=f[n-1]*10^k+n$

对于每一段位数个数相同的$n$（如$10\sim99,100\sim999,23333\sim66666,1018701389\sim2147483647$），$k$是个定值

然后就可以开心地分段矩阵乘法了，剩下的自己推吧

1 #include <bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 int mod;
5 struct mat
6 {
7     ll a[4][4];
8     int n, m;
9
10     mat()
11     {
12         memset(a, 0, sizeof(a));
13         n = 0, m = 0;
14     }
15
16     mat(int x, int y)
17     {
18         memset(a, 0, sizeof(a));
19         n = x, m = y;
20     }
21
22     mat operator* (const mat &rhs) const
23     {
24         mat ans;
25         ans.n = n, ans.m = rhs.m;
26         for(int i = 1; i <= n; ++i)
27             for(int j = 1; j <= rhs.m; ++j)
28                 for(int k = 1; k <= m; ++k)
29                     ans.a[i][j] = (ans.a[i][j] + a[i][k] * rhs.a[k][j]) % mod;
30         return ans;
31     }
32
33     mat operator^ (ll rhs) const
34     {
35         mat ans(n, n), b = *this;
36         for(int i = 1; i <= n; ++i)
37             ans.a[i][i] = 1;
38         for(; rhs; rhs >>= 1, b = b * b)
39             if(rhs & 1) ans = ans * b;
40         return ans;
41     }
42 };
43
44 int main()
45 {
46     ll n, c;
47     mat ans(1, 3), b(3, 3);
48     scanf("%lld%d", &n, &mod);
49     ans.a[1][3] = 1;
50     for(int i = 1; i <= 3; ++i)
51         for(int j = 1; j <= i; ++j)
52             b.a[i][j] = 1;
53     for(ll i = 10; ; i *= 10)
54     {
55         b.a[1][1] = i % mod;
56         if(i <= n) c = i / 10 * 9;
57         else c = n - i / 10 + 1;
58         ans = ans * (b ^ c);
59         if(i > n) break;
60     }
61     printf("%lld\n", ans.a[1][1]);
62     return 0;
63 }
View Code

posted @ 2016-07-14 00:41  CtrlCV  阅读(...)  评论(...编辑  收藏