思路: 矩阵快速幂
分析:
1 题目给定n只猫,每只猫的初始的花生的数量为0。现在有三种操作,g i 第i只猫加一个花生,e i 把第i只猫的所有花生全部吃完 s i j 把第i 和 j只猫的花生数进行交换
2 根据上面的三种操作那么我们能够举例n = 3的时候的三种操作。
对于g 1,我们把第一行的最后一位加1,这里增加了一列目的是为了能够求出和,因为初始化a b c都为0
1 0 0 1 a a+1
0 1 0 0 * b = b
0 0 1 0 c c
0 0 0 1 1 1
对于e 1,我们把第一行全部置为0,那么这样就是相当于吃掉全部的花生
0 0 0 0 a 0
0 1 0 0 * b = b
0 0 1 0 c c
0 0 0 1 1 1
对于 s 1 2
0 1 0 0 a b
1 0 0 0 * b = a
0 0 1 0 c c
0 0 0 1 1 1
3 那么我们只要先把k次的操作整合到一个矩阵A里面,然后求A^m,矩阵的最后一列的前n个数即为所求
4 由于矩阵乘法涉及到乘的次数越多,就越耗时间,因此我们需要在矩阵相乘的时候进行优化
代码:
/************************************************ * By: chenguolin * * Date: 2013-08-31 * * Address: http://blog.csdn.net/chenguolinblog * ************************************************/ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long int64; const int N = 105; int n , m , k; struct Matrix{ int64 mat[N][N]; Matrix operator*(const Matrix& ma)const{ Matrix tmp; for(int i = 0 ; i <= n ; i++){ for(int j = 0 ; j <= n ; j++){ tmp.mat[i][j] = 0; for(int k = 0 ; k <= n ; k++){ if(mat[i][k] && ma.mat[k][j]) tmp.mat[i][j] += mat[i][k]*ma.mat[k][j]; } } } return tmp; } }; void input(Matrix &ma){ char c; int x , y; memset(ma.mat , 0 , sizeof(ma.mat)); for(int i = 0 ; i <= n ; i++) ma.mat[i][i] = 1; while(k--){ scanf("%c" , &c); if(c == 'g'){ scanf("%d%*c" , &x); x--; ma.mat[x][n]++; } else if(c == 's'){ scanf("%d%d%*c" , &x , &y); x-- , y--; for(int i = 0 ; i <= n ; i++){ int tmp = ma.mat[x][i]; ma.mat[x][i] = ma.mat[y][i]; ma.mat[y][i] = tmp; } } else{ scanf("%d%*c" , &x); x--; for(int i = 0 ; i <= n ; i++) ma.mat[x][i] = 0; } } } void Pow(Matrix &ma){ Matrix ans; memset(ans.mat , 0 , sizeof(ans.mat)); for(int i = 0 ; i <= n ; i++) ans.mat[i][i] = 1; while(m){ if(m&1) ans = ans*ma; m >>= 1; ma = ma*ma; } for(int i = 0 ; i < n ; i++){ if(i) printf(" "); printf("%lld" , ans.mat[i][n]); } puts(""); } int main(){ Matrix ma; while(scanf("%d%d%d%*c" , &n , &m , &k) && n+m+k){ input(ma); Pow(ma); } return 0; }
时间: 2024-11-09 00:08:19