题目:Training little cats
链接:http://poj.org/problem?id=3735
分析:
1)将操作用矩阵表示出来,然后快速幂优化。
2)初始矩阵:$ left[ egin{array}{ccccc} 1 & a_1 & a_2 & ... & a_n end{array} ight] $
构造一个$ (n+1)*(n+1) $ 的单位矩阵T。
得花生:将第0行中得到花生的那一列赋为1.
$ left[ egin{array}{cccccc} 1 & 0 & ... & [1] & ... & 0 \ 0 & 1 & ... & 0 & ... & 0 \ ... & ... & ... & ... & ... & ... \ 0 & 0 & ... & 0 & ... & 1 end{array} ight] $
吃花生:将第得到花生的那一行那一列的元素赋为0;
$ left[ egin{array}{cccccc} 1 & 0 & ... & 0 & ... & 0 \ 0 & 1 & ... & 0 & ... & 0 \ ... & ... & ... & ... & ... & ... \ 0 & 0 & ... & [0] & ... & 0 \ ... & ... & ... & ... & ... & ... \ 0 & 0 & ... & 0 & ... & 1 end{array} ight] $
交换花生:就是交换两行,就是初等行变化。
$ left[ egin{array}{cccccc} 1 & 0 & ... & 0 & ... & 0 \ ... & ... & ... & ... & ... & ... \ ... & ... & 0 & ... & [1] & ... \ ... & ... & ... & ... & ... & ... \ ... & ... & [1] & ... & 0 & ... \ ... & ... & ... & ... & ... & ... \ 0 & 0 & ... & 0 & ... & 1 end{array} ight] $
3)T不停累乘操作矩阵,最后得到这一组的组操作矩阵。
4)快速幂求T^n,然后第一行就是答案。
5)注意longlong,虽然只有$10^9$次组操作,但每组操作都是100个得花生,还都给一只猫,就爆int了。
#include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long LL; struct Matrix{ int n; LL a[101][101]; void init(int _n,int f,int p=0,int pp=0){ n=_n; memset(a,0,sizeof a); if(f==-1)return; for(int i=0;i<=n;++i)a[i][i]=1; if(f==1)a[0][p]=1; if(f==2)a[p][p]=0; if(f==3){ a[p][p]=a[pp][pp]=0; a[p][pp]=a[pp][p]=1; } } }; Matrix operator*(Matrix& A,Matrix& B){ Matrix C;C.init(A.n,-1); for(int k=0,n=C.n;k<=n;++k) for(int i=0;i<=n;++i)if(A.a[i][k]) for(int j=0;j<=n;++j) C.a[i][j]+=A.a[i][k]*B.a[k][j]; return C; } Matrix operator^(Matrix A,int n){ Matrix Rt;Rt.init(A.n,0); for(;n;n>>=1){ if(n&1)Rt=Rt*A; A=A*A; } return Rt; } int main(){ int n,m,k,p,pp;char ch[1]; Matrix T,T1; for(;scanf("%d%d%d",&n,&m,&k);){ if(n==0 && m==0 && k==0)break; T.init(n,0); for(int i=1;i<=k;++i){ scanf("%s",ch); switch(ch[0]){ case 'g':scanf("%d",&p);T1.init(n,1,p);break; case 'e':scanf("%d",&p);T1.init(n,2,p);break; case 's':scanf("%d%d",&p,&pp);T1.init(n,3,p,pp); } T=T*T1; } T=T^m; for(int i=1;i<=n;++i)printf("%lld ",T.a[0][i]); puts(""); } return 0; }
6)可以直接把初始矩阵的效果叠加到T上面
#include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long LL; struct Matrix{ int n; LL a[101][101]; void init(int _n,int f){ n=_n; memset(a,0,sizeof a); if(f==-1)return; for(int i=0;i<=n;++i)a[i][i]=1; } }; Matrix operator*(Matrix& A,Matrix& B){ Matrix C;C.init(A.n,-1); for(int k=0,n=C.n;k<=n;++k) for(int i=0;i<=n;++i)if(A.a[i][k]) for(int j=0;j<=n;++j) C.a[i][j]+=A.a[i][k]*B.a[k][j]; return C; } Matrix operator^(Matrix A,int n){ Matrix Rt;Rt.init(A.n,0); for(;n;n>>=1){ if(n&1)Rt=Rt*A; A=A*A; } return Rt; } int main(){ int n,m,k,p,pp;char ch[1]; Matrix T; for(;scanf("%d%d%d",&n,&m,&k);){ if(n==0 && m==0 && k==0)break; T.init(n,0); for(int i=1;i<=k;++i){ scanf("%s",ch); switch(ch[0]){ case 'g':scanf("%d",&p);++T.a[0][p];break; case 'e':scanf("%d",&p); for(int i=0;i<=n;++i)T.a[i][p]=0; break; case 's':scanf("%d%d",&p,&pp); for(int i=0;i<=n;++i)swap(T.a[i][p],T.a[i][pp]); } } T=T^m; for(int i=1;i<=n;++i)printf("%lld ",T.a[0][i]); puts(""); } return 0; }