原题传送:http://poj.org/problem?id=3233
两个二分:二分 k ,二分矩阵。
求Sn = A + A2 + A3 + … + Ak。
首先我们能矩阵二分快速幂计算出Ak,那么我们对S再进行二分:
当k % 2 != 0则计算Ak+S(k-1),当k % 2 == 0时计算S(k/2) * (Ak/2 + E),这样就可以在log(k)的时间里算出Sk。
ps:这题有两个地方要注意,否则可能会TLE
1. 用 unsigned int,不要 long long
2. 取模运算效率很低,矩阵乘法单个元素最大值不是很大的情况下先算出来再取一次模更好。
View Code 200ms左右
1 #include <stdio.h> 2 #include <string.h> 3 const int maxn = 31; 4 struct mat 5 { 6 unsigned m[maxn][maxn]; 7 }a, E; 8 unsigned n, k, MOD; 9 10 mat operator *(mat u, mat v) 11 { 12 mat c; 13 memset(c.m, 0, sizeof c.m); 14 for(int i = 0; i < n; i ++) 15 for(int j = 0; j < n; j ++){ 16 for(int r = 0; r < n; r ++) 17 c.m[i][j] += u.m[i][r] * v.m[r][j]; 18 c.m[i][j] %= MOD; 19 } 20 return c; 21 } 22 23 mat operator +(mat u, mat v) 24 { 25 mat c; 26 for(int i = 0; i < n; i ++) 27 for(int j = 0; j < n; j ++) 28 c.m[i][j] = (u.m[i][j] + v.m[i][j]) % MOD; 29 return c; 30 } 31 32 mat cal(mat A, int x) 33 { 34 mat t = E; 35 for(; x; x >>= 1, A = A * A) 36 if(x & 1) t = t * A; 37 return t; 38 } 39 40 mat sum(int x) 41 { 42 if(x == 1) 43 return a; 44 if(x & 1) 45 return cal(a, x) + sum(x - 1); 46 else 47 return sum(x / 2) * (E + cal(a, x / 2)); 48 return a; 49 } 50 int main() 51 { 52 while(scanf("%d%d%d", &n, &k, &MOD) != EOF) 53 { 54 for(int i = 0; i < n; i ++) 55 { 56 for(int j = 0; j < n; j ++) 57 { 58 scanf("%u", &a.m[i][j]); 59 a.m[i][j] %= MOD; 60 E.m[i][j] = (i == j); 61 } 62 } 63 mat ans = sum(k); 64 for(int i = 0; i < n; i ++) 65 { 66 for(int j = 0; j < n-1; j ++) 67 printf("%u ", ans.m[i][j]); 68 printf("%u\n", ans.m[i][n - 1]); 69 } 70 } 71 return 0; 72 }