• [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;
    }
            
  • 相关阅读:
    CSS之表格边框合并、兄弟标签外边距合并、父子标签的外边距合并
    html之css选择器学习
    html5常见新增标签
    mysql之数据备份与恢复
    mysql之用户权限管理
    mysql之用户管理
    mysql之全球化和本地化:字符集、校对集、中文编码问题
    Sublime Text 3 安装与配置
    CSS 自适应
    php 验证码代码
  • 原文地址:https://www.cnblogs.com/hjj1871984569/p/10034954.html
Copyright © 2020-2023  润新知