【题目链接】 http://poj.org/problem?id=3735
【题目大意】
有一排小猫,给出一系列操作,包括给一只猫一颗花生,
让某只猫吃完所有的花生以及交换两只猫的花生,
求完成m次操作集合之后每只猫的花生数量
【题解】
创建一个1*(n+1)的初始矩阵,
对于给第i只猫一个花生就相当于乘上修改了A[0][i]的单位矩阵
如给第一只猫一个花生就修改A[0][1]为1
得到:
1 1 0 0
0 1 0 0
0 0 1 0
0 0 0 1
然后我们用初始矩阵去乘这个矩阵,就完成了加的操作
对于让第i只猫吃完所有的花生,我们将A[i][i]修改为0
如让第三只猫吃完花生,那么就相当于将A[3][3]改为0
得到
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 0
然后我们用初始矩阵去乘这个矩阵,就完成了清零的操作
对于交换花生的操作,我们交换单位矩阵的第x和y行,然后相乘即可
比如交换第一只猫和第三只猫的花生,我们就得到
1 0 0 0
0 0 0 1
0 0 1 0
0 1 0 0
乘到初始矩阵上即可
我们发现经过这些操作,我们最后会得到一个操作集合的矩阵表达
而这些操作的变换其实不用整个乘上矩阵,只要直接修改单位矩阵的部分值即可
第一种操作的影响可以转化为A[0][x]++
第二种操作的影响可以转化为A[0~n][x]=0
第三种操作的影响可以转化为i_0^n swap(A[i][x],A[i][y])
那么我们直接计算转置矩阵即可。
【代码】
#include <cstdio> #include <vector> #define rep(i,n) for(int i=0;i<n;i++) using namespace std; typedef long long LL; typedef vector<vector<LL> > mat; LL n,m,k,x,y; char op[10]; mat mul(mat &A,mat &B){ mat C(A.size(),vector<LL>(B[0].size())); rep(i,A.size())rep(k,B.size())if(A[i][k]){ rep(j,B[0].size())C[i][j]+=A[i][k]*B[k][j]; }return C; } mat pow(mat A,LL n){ mat B(A.size(),vector<LL>(A.size())); rep(i,A.size())B[i][i]=1; for(;n;n>>=1){if(n&1)B=mul(B,A);A=mul(A,A);} return B; } int main(){ while(scanf("%lld%lld%lld",&n,&m,&k),n+m+k){ mat A(n+1,vector<LL>(n+1)); rep(i,n+1)A[i][i]=1; while(k--){ scanf("%s",&op); if(op[0]=='g'){ scanf("%lld",&x); A[0][x]++; }else if(op[0]=='e'){ scanf("%lld",&x); rep(i,n+1)A[i][x]=0; }else{ scanf("%lld%lld",&x,&y); rep(i,n+1)swap(A[i][x],A[i][y]); } }if(m){ A=pow(A,m); printf("%lld",A[0][1]); for(int i=2;i<=n;i++)printf(" %lld",A[0][i]); puts(""); }else{ printf("0"); rep(i,n-1)printf(" 0"); puts(""); } }return 0; }