这道题的思想很简单,其实,就是将线性转换的关系,用一个转换矩阵来表示。
由于置0还有交换操作,在线性代数中,都有相应的操作相对应,见下面的3 4点
为了使得+1操作也有相应的操作相对应,只需要引入一只虚构的猫,使得加1的操作,就是加上最后一行
引入虚构的猫之后,就使得转移矩阵的大小为(n+1)*(n+1)
对于转移矩阵的构造,可以用如下方法:
1.初始化一个(n+1)*(n+1)的单位阵
2.对于g num1操作,使得矩阵的num1的最后一个元素加1,等价于加上最后一行,因为单位阵的最后一行是 0 0 0... 1
3.对于e num1操作,使得矩阵的num1行置0
4.对于s num1 num2操作,使得矩阵的num1行和num2行互换
此外,由于0<=m<=1000000000,所以,在进行多次的转换矩阵的计算时,应该使用二分法来求解矩阵乘积
还有,计算的结果,会超过int的范围,应该使用__int64(C++环境) 或者long long(G++环境)类型来表示
#include <iostream>
using namespace std;
const int SIZE = 103;
#define LAST (N + 1)
__int64 nuts[SIZE][SIZE];
__int64 transform[SIZE][SIZE];
__int64 result[SIZE][SIZE];//用于存放矩阵乘法的中间结果
__int64 M;
int N, K;
char c;
int num1, num2;
__int64 temp;
int i, j, k;
inline void init()
{
//在OJ上,不一定能够安全执行
//可能出现run time error
memset(transform, 0, sizeof(transform) );
/*for(i = 1; i <= LAST; ++i)
{
for(j = 1; j <= LAST; ++j)
{
transform[i][j] = 0;
}
}*/
for(i = 1; i <= LAST; ++i)
{
transform[i][i] = 1;
}
while(K--)
{
getchar();
scanf("%c", &c);
if('g' == c)
{
scanf("%d", &num1);
transform[num1][LAST] += 1;
}
else if('s' == c)
{
scanf("%d %d", &num1, &num2);
for(i = 1; i <= LAST; ++i)
{
temp = transform[num1][i];
transform[num1][i] = transform[num2][i];
transform[num2][i] = temp;
}
}
else
{
scanf("%d", &num1);
for(i = 1; i <= LAST; ++i)
{
transform[num1][i] = 0;
}
}
}
return;
}
inline void run()
{
memset(nuts, 0, sizeof(nuts));
/*for(i = 1; i <= LAST; ++i)
{
for(j = 1; j <= LAST; ++j)
{
nuts[i][j] = 0;
}
}*/
for(i = 1; i <= LAST; ++i)
{
nuts[i][i] = 1;
}
//当输入的m为时,由于函数开头的初始化
//结果也是正确的
while(M > 0)
{
if(M & 1) //等价于1 == m % 2
{
memset(result, 0, sizeof(result));
/*for(i = 1; i <= LAST; ++i)
{
for(j = 1; j <= LAST; ++j)
{
result[i][j] = 0;
}
}*/
for(i = 1; i <= LAST; ++i)
{
for(j = 1; j <= LAST; ++j)
{
for(k = 1; k <= LAST; ++k)
{
if(transform[i][k] && nuts[k][j])
{
result[i][j] += transform[i][k] * nuts[k][j];
}
}
}
}
for(i = 1; i <= LAST; ++i)
for(j = 1; j <= LAST; ++j)
{
nuts[i][j] = result[i][j];
}
}
M = M >> 1; //等价与m = m / 2;
memset(result, 0, sizeof(result));
/*for(i = 1; i <= LAST; ++i)
{
for(j = 1; j <= LAST; ++j)
{
result[i][j] = 0;
}
}*/
for(i = 1; i <= LAST; ++i)
{
for(j = 1; j <= LAST; ++j)
{
for(k = 1; k <= LAST; ++k)
{
if(transform[i][k] && transform[k][j])
{
result[i][j] += transform[i][k] * transform[k][j];
}
}
}
}
for(i = 1; i <= LAST; ++i)
for(j = 1; j <= LAST; ++j)
{
transform[i][j] = result[i][j];
}
}
//output
//事实上,转移矩阵的最后一列,就是结果
for(i = 1; i <= N; ++i)
{
printf("%I64d ", nuts[i][LAST]);
}
printf("/n");
return;
}
int main()
{
while(scanf("%d %I64d %d", &N, &M, &K) && (N + M + K))
{
init();
run();
}
return 0;
}