[BZOJ2326] [HNOI2011] 数学作业 (矩阵乘法)
Description
Input
Output
Sample Input
Sample Output
HINT
Source
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 }