[矩阵十题第七题]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 }
posted @ 2017-03-17 21:38  阿波罗2003  阅读(511)  评论(0编辑  收藏  举报