思路: 对于第一种操作g i,我们在单位矩阵基础上使Mat[0][i]变为1,例如g 1:
1 1 0 0
0 1 0 0
0 0 1 0
0 0 0 1,显然[1 0 0 0]*Mat = [1 1 0 0]
对于第二种操作e i,我们在单位矩阵基础使第i列 等于0,例如e 2:
1 0 0 0
0 1 0 0
0 0 0 0
0 0 0 1, 显然[1 2 3 4]*Mat = [1 2 0 4]
对于第三种操作s i j,我们在单位矩阵基础上使第i列与第j互换,例如s 1 2:
1 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0,显然[1 2 0 4]*Mat = [1 4 0 2]
现在,对于每一个操作我们都可以得到一个转置矩阵,把k个操作的矩阵相乘我们可以得到一个新的转置矩阵T。
A * T 表示我们经过一组操作,类似我们可以得到经过m组操作的矩阵为 A * T ^ m,最终矩阵的[0][1~n]即为答案。
构造矩阵T:
我们以单位矩阵为基础:
对于第一种操作g i,我们使Mat[0][i] = Mat[0][i] + 1;对于第二种操作e i,我们使矩阵的第i列清零;
对于第三种操作s i j,我们使第i列与第j列互换。
至此,构造转置矩阵T就完成了,接下来只需用矩阵快速幂求出 A * T ^ m即可,还有一个注意的地方,该题需要用到long long。
因为矩阵的乘法符合结合率,所以我们可以先算T^m,得到t,又因为A为1,0,0……;所以A*t为t的第一行。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
const int maxn = 108;
using namespace std;
struct mat{//套路0.0;
__int64 v[maxn][maxn];
};
int n, m;
//矩阵乘法优化
mat matrix_mul(mat a, mat b) {
mat c;
memset(c.v, 0, sizeof(c.v));
int i, j, k;
for(i = 0; i <= n; i++)
for(j = 0; j <= n; j++)
if (a.v[i][j])
for(k = 0; k <= n; k++)
c.v[i][k] += a.v[i][j]*b.v[j][k];
return c;
}
int main() {
int k;
while(scanf("%d%d%d", &n, &m, &k) && n) {
char c[2];//套路0.0;
mat p, t;
memset(p.v, 0, sizeof(p.v));
memset(t.v, 0, sizeof(t.v));
for(int i = 0; i <= n; i++) {
p.v[i][i] = 1;
t.v[i][i] = 1;
}
while(k--) {
scanf("%s", c);
if (c[0] == 'g') {
int num;
scanf("%d", &num);
p.v[0][num]++;
}
else if (c[0] == 's') {
int i, j;
scanf("%d%d", &i, &j);
for(int h = 0; h <= n; h++) {
__int64 tmp = p.v[h][i];
p.v[h][i] = p.v[h][j];
p.v[h][j] = tmp;
}
}
else {
int j;
scanf("%d", &j);
for(int i = 0; i <= n; i++)
p.v[i][j] = 0;
}
}
while(m) {//矩阵快速幂
if (m & 1)
t = matrix_mul(t, p);
m >>= 1;
p = matrix_mul(p, p);
}
for(int i = 1; i <= n; i++)
printf("%I64d ", t.v[0][i]);
printf("\n");
}
return 0;
}