[POJ3735]Training little cats

题目: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;
}
        
原文地址:https://www.cnblogs.com/hjj1871984569/p/10034954.html