我们看到这个题,很容易想到矩阵快速幂的做法。因为题目中两个条件实在太显眼:
- All the cats perform a sequence of these moves and must repeat it m m m times!
- m ≤ 1 0 10 m\leq 10^{10} m≤1010
一个相同的操作,做 1 0 10 10^{10} 1010 次,肯定是矩阵快速幂,问题就是我们如何把三个操作转化为 ( n + 1 ) × ( n + 1 ) (n+1)\times (n+1) (n+1)×(n+1) 的矩阵 o p t opt opt, o p t opt opt 一开始是一个单位矩阵。
首先我们先确定一个
a
n
s
ans
ans 矩阵,
a
n
s
1
,
i
ans_{1,i}
ans1,i 表示第
i
i
i 只猫的花生数。联想到花生米@花少北。 那么一开始矩阵就是长这样:
[ 0 ⋯ 0 ] \begin{bmatrix}0&\cdots&0\end{bmatrix} [0⋯0]
我们先来分析三个操作:
g x
。给第 x x x 只猫加一颗花生,我们可以采用一个小技巧:扩充矩阵。我们先把 a n s ans ans 矩阵变化一下,变成 n n n 个 0 0 0, 1 1 1 个 1 1 1,如下:
[ 0 ⋯ 0 1 ] \begin{bmatrix}0&\cdots&0\ 1\end{bmatrix} [0⋯0 1]
那么我们只需要给 o p t n + 1 , x opt_{n+1,x} optn+1,x 加上一个 1 1 1,就可以满足这个要求。因为在乘法是会有 a n s i , x + = a n s 1 , n + 1 × o p t n + 1 , x ans_{i,x}+=ans_{1,n+1}\times opt_{n+1,x} ansi,x+=ans1,n+1×optn+1,x。
-
e x
。这个操作最简单。我们直接清空 o p t opt opt 中第 x x x 列即可。 -
s x y
。交换操作也很简单,也就是把 o p t opt opt 中 x , y x,y x,y 两列交换一下即可。
最后快速幂计算即可。
注意一下本题中这是一个稀疏矩阵,我们可以用一个小优化来通过老爷机的评测。 详情见代码注释。
//Don't act like a loser.
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAXN=110;
int n,m,k;
struct matrix {
long long data[MAXN][MAXN];
int col,row;
void clear() {
col=row=0;
for(int i=1;i<=n+1;i++) {
for(int j=1;j<=n+1;j++) {
data[i][j]=0;
}
}
}
void initialize() {
clear();
col=row=n+1;
for(int i=1;i<=n+1;i++) {
data[i][i]=1;
}
}
inline matrix operator *(matrix& b)const {
matrix ans;
ans.clear();
for(int i=1;i<=col;i++) {
for(int k=1;k<=row;k++) {
if(data[i][k]==0) continue;//这里有一个小优化~
for(int j=1;j<=b.row;j++) {
ans.data[i][j]+=data[i][k]*b.data[k][j];
}
}
}
ans.col=col;
ans.row=b.row;
return ans;
}
};
matrix ans;
matrix opt;
inline void qpow(int y) {
while(y) {
if(y&1) {
ans=ans*opt;
}
opt=opt*opt;
y>>=1;
}
}
signed main() {
while(1) {
scanf("%d%d%d",&n,&m,&k);
if(n==0&&m==0&&k==0) break;
ans.clear();
ans.col=1;
ans.row=n+1;
for(int i=1;i<=n;i++) {
ans.data[1][i]=0;
}
ans.data[1][n+1]=1;
opt.initialize();
for(int i=1;i<=k;i++) {
char ch[5];
int x,y;
scanf("%s",ch);
if(ch[0]=='s')
scanf("%d%d",&x,&y);
else
scanf("%d",&x);
if(ch[0]=='s') {
for (int j=1;j<=n+1;++j)
swap(opt.data[j][x],opt.data[j][y]);
}
if(ch[0]=='g') {
opt.data[n+1][x]++;
}
if(ch[0]=='e') {
for (int j=1; j<=n+1;++j)
opt.data[j][x]=0;
}
}
qpow(m);
for(int i=1;i<=n;i++) {
printf("%lld ",ans.data[1][i]);
}
printf("\n");
}
return 0;
}