题目链接
题目大意
给了n,m,k分别代表有几只猫,同样的一套动作要做m次,这套动作有k个
有n只猫,给每只猫放食物:
g i 代表给第i只猫加一块食物
e i 代表第i只猫吃完自己的所有食物
s i j 代表第i只猫,与第j只猫的食物互换
问这一套动作,做m次,每个猫有多少食物
注:多组输入
题目思路
看到m这么多次比较容易想到矩阵快速幂,但是自己没写过类似的,构造有点困难。
思考如何实现加1,其实只需要把矩阵变为(n+1)*(n+1)即可
当g i 时让base[i][n+1]–;
当 e i 时让这一行全部为0;
当s i j时交换两行即可。
注意
要优化矩阵的乘法,因为有很多0元素,不然会tle
优化代码
for(int i=0;i<=n;i++){
for(int k=0;k<=n;k++){
if(a.v[i][k])
for(int j=0;j<=n;j++)
if(b.v[k][j])
c.v[i][j]+=a.v[i][k]*b.v[k][j];
}
}
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e2+10;
char opt;
int m,n,k,x,y;
ll ans[maxn][maxn],base[maxn][maxn],temp[maxn][maxn];
//注意设为long long
void init(){
memset(ans,0,sizeof(ans));
memset(base,0,sizeof(base));
for(int i=1;i<=n+1;i++){//注意要多一行
ans[i][i]=base[i][i]=1;
}
}
void mul1(int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
temp[i][j]=ans[i][j];
ans[i][j]=0;
}
}
for(int i=1;i<=n;i++){
for(int k=1;k<=n;k++){
if(temp[i][k]){//注意稀疏矩阵的乘法
for(int j=1;j<=n;j++){
ans[i][j]+=temp[i][k]*base[k][j];
}
}
}
}
}
void mul2(int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
temp[i][j]=base[i][j];
base[i][j]=0;
}
}
for(int i=1;i<=n;i++){
for(int k=1;k<=n;k++){
for(int j=1;j<=n;j++){
if(temp[i][k]){
base[i][j]+=temp[i][k]*temp[k][j];
}
}
}
}
}
void qpow(int n,int k){
while(k>0){
if(k&1){
mul1(n);
}
k=k>>1;
mul2(n);
}
}
signed main(){
while(scanf("%d %d %d",&n,&m,&k)==3&&n){
init();
for(int i=1;i<=k;i++){
scanf(" %c %d",&opt,&x);//最前面加空格,清空缓冲区
if(opt=='g'){
base[x][n+1]++;
}else if(opt=='e'){
for(int j=1;j<=n+1;j++){//这一行全部清0
base[x][j]=0;
}
}else if(opt=='s'){
scanf("%d",&y);
swap(base[x],base[y]);//两行交换
}
}
qpow(n+1,m);
for(int i=1;i<=n;i++){
printf("%lld%c",ans[i][n+1],i==n?'\n':' ');
}
}
return 0;
}