[矩阵十题第七题]vijos 1067 Warcraft III 守望者的烦恼 -矩阵快速幂
背景
守望者-warden,长期在暗夜精灵的的首都艾萨琳内担任视察监狱的任务,监狱是成长条行的,守望者warden拥有一个技能名叫“闪烁”,这个技能可以把她传送到后面的监狱内查看,她比较懒,一般不查看完所有的监狱,只是从入口进入,然后再从出口出来就算完成任务了。
描述
头脑并不发达的warden最近在思考一个问题,她的闪烁技能是可以升级的,k级的闪烁技能最多可以向前移动k个监狱,一共有n个监狱要视察,她从入口进去,一路上有n个监狱,而且不会往回走,当然她并不用每个监狱都视察,但是她最后一定要到第n个监狱里去,因为监狱的出口在那里,但是她并不一定要到第1个监狱。
守望者warden现在想知道,她在拥有k级闪烁技能时视察n个监狱一共有多少种方案?
格式
输入格式
第一行是闪烁技能的等级k(1<=k<=10)
第二行是监狱的个数n(1<=n<=2^31-1)
输出格式
由于方案个数会很多,所以输出它 mod 7777777后的结果就行了
样例1
样例输入1
2
4
样例输出1
5
限制
各个测试点1s
提示
把监狱编号1 2 3 4,闪烁技能为2级,
一共有5种方案
→1→2→3→4
→2→3→4
→2→4
→1→3→4
→1→2→4
小提示:建议用int64,否则可能会溢出
来源
杜杜我爱你个人原创
最朴实的dp方程
根据加法原理,把所有可以到达n号监狱的出发点(n-i)的值累加起来。
再看数据范围,O(nk)果断超时,不解释(除非用超算评测或许还可以AC)
总觉得和线性递推长得差不多,于是考虑用矩阵快速幂来优化。首先表示出最初的状态
其中f[0] = 1。接着按照套路来进行矩阵乘法得到下一项
因此我们有
又因为矩阵乘法满足结合律,所以就对那么看起来由0和1构成的矩阵进行快速幂就好了。
Code
1 /** 2 * vijos 3 * Problem#1067 4 * Accepted 5 * Time:46ms 6 * Memory:1016k 7 */ 8 #include<iostream> 9 #include<cstdio> 10 #include<cctype> 11 #include<cstring> 12 #include<cstdlib> 13 #include<fstream> 14 #include<sstream> 15 #include<algorithm> 16 #include<map> 17 #include<set> 18 #include<queue> 19 #include<vector> 20 #include<stack> 21 using namespace std; 22 typedef bool boolean; 23 #define INF 0xfffffff 24 #define smin(a, b) a = min(a, b) 25 #define smax(a, b) a = max(a, b) 26 template<typename T> 27 inline void readInteger(T& u){ 28 char x; 29 int aFlag = 1; 30 while(!isdigit((x = getchar())) && x != '-'); 31 if(x == '-'){ 32 x = getchar(); 33 aFlag = -1; 34 } 35 for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); 36 ungetc(x, stdin); 37 u *= aFlag; 38 } 39 40 #define moder 7777777 41 42 typedef class Matrix { 43 public: 44 int* p; 45 int lines, cols; 46 Matrix():p(NULL), lines(0), cols(0) { } 47 Matrix(int lines, int cols):lines(lines), cols(cols) { 48 p = new int[(lines * cols)]; 49 } 50 51 int* operator [](int pos) { 52 return p + pos * cols; 53 } 54 55 Matrix operator *(Matrix b) { 56 if(cols != b.lines) return Matrix(); 57 Matrix res = Matrix(lines, b.cols); 58 for(int i = 0; i < lines; i++) { 59 for(int j = 0; j < b.cols; j++) { 60 res[i][j] = 0; 61 for(int k = 0; k < cols; k++) { 62 (res[i][j] += ((*this)[i][k] * 1LL * b[k][j]) % moder) %= moder; 63 } 64 } 65 } 66 return res; 67 } 68 }Matrix; 69 70 template<typename T> 71 T pow(T a, int pos) { 72 if(pos == 1) return a; 73 T temp = pow(a, pos / 2); 74 if(pos & 1) return temp * temp * a; 75 return temp * temp; 76 } 77 78 int k, n; 79 Matrix unit; 80 Matrix org; 81 82 inline void init() { 83 readInteger(k); 84 readInteger(n); 85 } 86 87 inline void solve() { 88 org = Matrix(k, 1); 89 org[k - 1][0] = 1; 90 for(int i = k - 2; i >= 0; i--) { 91 org[0][i] = 0; 92 for(int j = i; j < k; j++) 93 org[0][i] += org[0][j]; 94 } 95 if(n < k) { 96 printf("%d", org[0][n]); 97 return; 98 } 99 unit = Matrix(k, k); 100 for(int i = 0; i < k; i++) 101 unit[0][i] = 1; 102 for(int i = 1; i < k; i++) 103 for(int j = 0; j < k; j++) 104 unit[i][j] = (i == j + 1) ? (1) : (0); 105 Matrix res = pow(unit, n - k + 1) * org; 106 printf("%d", res[0][0]); 107 } 108 109 int main() { 110 init(); 111 solve(); 112 return 0; 113 }