hdu 4291 A Short problem
http://acm.hdu.edu.cn/showproblem.php?pid=4291
一道矩阵快速幂的题目,给出递推关系,求目标函数的值。
对递推的题比较陌生,刚开始的时候直接将快速幂套进去,过了sample以后就果断交上去了,没想到居然wa了。搞了一段时间,认真检查了代码无数次,还是找不到问题。
然后突然被我想到一个相当大的问题。在直接暴力算的时候,算出一层的结果是已经取模以后的结果,可是题目要的是最终结果取模,如果直接套进去算就会发生偏差。对于最外面一层的的结果模10^9+7,我们需要找到这一层的循环节,曾而降低里面那层得到结果的数据规模。暴力打表,得出最外面一层的循环节大小是222222224。这样还没完,因为求解中有3层,所以我们需要继续求循环节,求得最里面一层的循环节长度是183120。然后,把它们建立成表,做成非递归的形式迭代求解。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 6 using namespace std; 7 typedef __int64 ll; 8 const int mod[3] = {1000000007, 222222224, 183120}; 9 const int matSize = 2; 10 int curMod; 11 12 struct Matrix { 13 ll val[matSize][matSize]; 14 15 Matrix(bool Init = false) { 16 for (int i = 0; i < matSize; i++) { 17 for (int j = 0; j < matSize; j++) { 18 val[i][j] = 0; 19 } 20 if (Init) val[i][i] = 1; 21 } 22 } 23 24 25 void print() { 26 for (int i = 0; i < matSize; i++) { 27 for (int j = 0; j < matSize; j++) { 28 printf("%I64d ", val[i][j]); 29 } 30 puts(""); 31 } 32 puts("~~~"); 33 } 34 } Base; 35 36 Matrix operator * (Matrix _a, Matrix _b) { 37 Matrix ret = Matrix(); 38 39 for (int i = 0; i < matSize; i++) { 40 for (int k = 0; k < matSize; k++) { 41 if (_a.val[i][k]) { 42 for (int j = 0; j < matSize; j++) { 43 ret.val[i][j] += (_a.val[i][k] * _b.val[k][j]) % curMod; 44 ret.val[i][j] %= curMod; 45 } 46 } 47 } 48 } 49 50 return ret; 51 } 52 53 Matrix operator ^ (Matrix _a, ll _p) { 54 Matrix ret = Matrix(true); 55 56 while (_p) { 57 if (_p & 1) { 58 ret = ret * _a; 59 } 60 _a = _a * _a; 61 _p >>= 1; 62 } 63 64 return ret; 65 } 66 67 void initBase(ll _k = 1, ll _a = 3) { 68 Base.val[0][1] = _k; 69 Base.val[1][1] = _a; 70 Base.val[0][0] = 0; 71 Base.val[1][0] = 1; 72 } 73 74 ll fun(ll _x, int modKind) { 75 Matrix ret = Matrix(); 76 77 curMod = mod[modKind]; 78 ret.val[0][0] = 0; 79 ret.val[0][1] = 1; 80 81 ret = ret * (Base ^ _x); 82 // ret.print(); 83 84 return ret.val[0][0]; 85 } 86 87 ll deal(ll _x) { 88 ll ret = _x; 89 90 for (int i = 2; i >= 0; i--) { 91 ret = fun(ret, i); 92 } 93 94 return ret; 95 } 96 97 int main() { 98 ll n; 99 // Matrix tmp = Matrix(true); 100 101 initBase(); 102 // Base.print(); 103 /* 104 for (ll i = 0; ; i++) { 105 int last = tmp.val[0][0]; 106 107 tmp = tmp * Base; 108 if (last == 0 && tmp.val[0][0] == 1) { 109 printf("reach %I64d\n", i); 110 } 111 } 112 */ 113 while (~scanf("%I64d", &n)) { 114 printf("%I64d\n", deal(n)); 115 } 116 117 return 0; 118 }
——written by Lyon