poj 3735 Training little cats
http://poj.org/problem?id=3735
矩阵快速幂的题。表示yy了很长一段时间才想到怎么构造矩阵。。。。不过过了sample以后就1y了!
简单的说一下构造的方法:一个原始矩阵(代码里面的Base)只用到第一行。前面n个表示的是每只猫拥有的食物,因为刚开始的时候所有猫都是没有食物的,所以全部设置为0。紧接着的n个数表示的是每一个循环里食物数量的改变值。然后就是每个循环的操作,也就是代码里的op矩阵。这个矩阵是这样设置的,初始化的时候,分成四块,其中有三块矩阵是单位矩阵。然后,对于每一个题目要求的操作,食物加一就是Base矩阵后半部分相应位置加一,食物交换就是op矩阵相应的两列交换过来,清空食物就是将op的相应的位置(对应这里的猫拥有的食物的位置)以及将Base中循环里的食物的数量改变值清空。
可以这样想,现在我们需要的是利用矩阵来简化100个操作的循环,那么要怎样设置矩阵才能实现这样的功能呢?其实将每次循环后每只猫拥有的食物的数量和循环前做对比,可以发现操作后的每个位置的值只是由两部分组成。一部分是上一循环结束后,某一只猫拥有的食物的量,另一部分是循环过后对于这个位置的猫的食物的变化量。于是,处理好操作矩阵,每次就可以用同样的矩阵来模拟循环的操作了。
代码如下:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 6 using namespace std; 7 typedef __int64 ll; 8 const int matSize = 200; 9 int calSize = matSize; 10 11 struct Matrix { 12 ll val[matSize][matSize]; 13 14 Matrix(bool Init = false) { 15 for (int i = 0; i < calSize; i++) { 16 for (int j = 0; j < calSize; j++) { 17 val[i][j] = 0; 18 } 19 if (Init) val[i][i] = 1; 20 } 21 } 22 23 void print() { 24 for (int i = 0; i < calSize; i++) { 25 for (int j = 0; j < calSize; j++) { 26 printf("%I64d ", val[i][j]); 27 } 28 puts(""); 29 } 30 puts("~~~"); 31 } 32 } Base, op; 33 34 Matrix operator * (Matrix &_a, Matrix &_b) { 35 Matrix ret = Matrix(); 36 37 for (int i = 0; i < calSize; i++) { 38 for (int k = 0; k < calSize; k++) { 39 if (_a.val[i][k]) { 40 for (int j = 0; j < calSize; j++) { 41 ret.val[i][j] += _a.val[i][k] * _b.val[k][j]; 42 } 43 } 44 } 45 } 46 47 return ret; 48 } 49 50 Matrix operator ^ (Matrix &_a, ll _p) { 51 Matrix ret = Matrix(true); 52 53 while (_p) { 54 if (_p & 1) { 55 ret = ret * _a; 56 } 57 _a = _a * _a; 58 _p >>= 1; 59 } 60 61 return ret; 62 } 63 64 Matrix operator + (Matrix &_a, Matrix &_b) { 65 for (int i = 0; i < calSize; i++) { 66 for (int j = 0; j < calSize; j++) { 67 _a.val[i][j] = _a.val[i][j] + _b.val[i][j]; 68 } 69 } 70 71 return _a; 72 } 73 74 void deal(int n, ll m, int k) { 75 char buf[3]; 76 int a, b; 77 int pos[101]; 78 79 calSize = n << 1; 80 op = Matrix(); 81 Base = Matrix(); 82 for (int i = 0; i < n; i++) { 83 pos[i] = i; 84 op.val[i][i] = op.val[i + n][i] = op.val[i + n][i + n] = 1; 85 } 86 while (k--) { 87 scanf("%s", buf); 88 switch (buf[0]) { 89 case 'g': 90 scanf("%d", &a); 91 Base.val[0][pos[a - 1] + n]++; 92 break; 93 case 'e': 94 scanf("%d", &a); 95 Base.val[0][pos[a - 1] + n] = 0; 96 op.val[pos[a - 1]][a - 1] = 0; 97 break; 98 case 's': 99 scanf("%d%d", &a, &b); 100 swap(pos[a - 1], pos[b - 1]); 101 for (int i = 0, endi = n << 1; i < endi; i++) { 102 swap(op.val[i][a - 1], op.val[i][b - 1]); 103 } 104 break; 105 } 106 } 107 // puts("Base"); 108 // Base.print(); 109 op = op ^ m; 110 // puts("op"); 111 // op.print(); 112 113 Matrix ans = Base * op; 114 // ans.print(); 115 116 for (int i = 0; i < n; i++) { 117 if (i) putchar(' '); 118 printf("%I64d", ans.val[0][i]); 119 } 120 puts(""); 121 } 122 123 int main() { 124 int n, k; 125 ll m; 126 127 freopen("in", "r", stdin); 128 while (~scanf("%d%I64d%d", &n, &m, &k)&& (n || m || k)) { 129 deal(n, m, k); 130 } 131 132 return 0; 133 }
——written by Lyon