POJ 3735 Training little cats 矩阵快速幂
http://poj.org/problem?id=3735
给定一串操作,要这个操作连续执行m次后,最后剩下的值。
记矩阵T为一次操作后的值,那么T^m就是执行m次的值了。(其实这个还不太理解,但是数据一相乘,就是ans)
构造一个0--n的单位矩阵,用第0行作为各个猫的值,这样的话,用A={1,0,0,0}一乘就是每个毛的ans。
构造单位矩阵的意义就是他们矩阵自己相乘的时候,能够保留自己的值。
这个矩阵很分散,0的那些可以特判掉不枚举多一程O(n)了。这需要你的矩阵乘法是一个一个加上去的,而不是集中一起加上去的。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 100 + 2; struct Matrix { LL a[maxn][maxn]; int row; int col; }; struct Matrix c; //这个要多次用到,栈分配问题,maxn不能开太大, struct Matrix matrix_mul (struct Matrix a,struct Matrix b,int MOD) { //求解矩阵a*b%MOD struct Matrix c = {0}; //LL的时候更加是,空间是maxn*maxn的,这样时间用得很多 c.row=a.row; //行等于第一个矩阵的行 c.col=b.col; //列等于第二个矩阵的列 for (int i = 0; i <= a.row; ++i) { for (int k = 0; k <= a.col; ++k) { if (a.a[i][k]) {//应付稀疏矩阵 for (int j = 0; j <= b.col; ++j) { c.a[i][j] += a.a[i][k] * b.a[k][j]; } } } } return c; } struct Matrix quick_matrix_pow (struct Matrix ans,struct Matrix base,int n,int MOD) { //求解a*b^n%MOD // cout << n << endl; while (n) { if (n&1) { ans=matrix_mul(ans,base,MOD);//传数组不能乱传,不满足交换律 } n>>=1; base=matrix_mul(base,base,0); } return ans; } int n, m, k; void work() { struct Matrix b = {0}; b.row = b.col = n; for (int i = 0; i <= n; ++i) { b.a[i][i] = 1; } for (int i = 1; i <= k; ++i) { char str[11]; int a, c; scanf("%s", str); if (str[0] == 'g') { scanf("%d", &a); ++b.a[0][a]; } else if (str[0] == 'e') { scanf("%d", &a); for (int j = 0; j <= n; ++j) { b.a[j][a] = 0; } } else { scanf("%d%d", &a, &c); for (int j = 0; j <= n; ++j) { swap(b.a[j][a], b.a[j][c]); } } } // for (int i = 0; i <= n; ++i) { // for (int j = 0; j <= n; ++j) { // cout << b.a[i][j] << " "; // } // cout << endl; // } struct Matrix tt = {0}; tt.row = 1; tt.col = n; tt.a[0][0] = 1; struct Matrix ans = quick_matrix_pow(tt, b, m, 111); for (int i = 1; i <= n; ++i) { printf("%lld ", ans.a[0][i]); } printf("\n"); } int main() { #ifdef local freopen("data.txt","r",stdin); #endif while (scanf("%d%d%d", &n, &m, &k) != EOF && n + m + k) work(); return 0; }
既然选择了远方,就要风雨兼程~
posted on 2016-10-09 15:55 stupid_one 阅读(223) 评论(0) 编辑 收藏 举报