poj 3735 Training little cats 题解(构造,矩阵)

该博客介绍了如何利用矩阵快速幂解决poj 3735问题,该问题涉及交换序列元素、单点加一和置零操作。博主通过构造转移矩阵T并进行矩阵乘法,最终得出序列在多次操作后的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:
poj

题意简述

给定一个长度为 n ( &lt; = 100 ) n(&lt;=100) n(<=100)的序列,和一组操作。一组操作由 k ( &lt; = 100 ) k(&lt;=100) k(<=100)个操作组成,有三种,分别是:

  1. 交换两个数
  2. 某个单独位置++
  3. 某个单独位置=0

重复 m ( &lt; = 1 e 9 ) m(&lt;=1e9) m(<=1e9)次。求最后的序列。

思路

我们发现,要重复很多次,但是长度和一组的数量都不大,而且是立方的复杂度。

立方?!想到了什么!

yeah♂, 矩阵。配一张奆佬的图
原链接,这篇讲的很好

也就是说,我们构造一个转移矩阵 T T T,一开始是一个单位矩阵(对角线是 1 1 1的矩阵)
对于:

  1. 交换 ( a , b ) (a,b) (a,b):交换 T T T的第 a , b a,b a,b两行( O ( n ) O(n) O(n)
  2. a a a++: T T T a a a行第 n + 1 n+1 n+1个位置++
  3. a a a清零:清零 T T T a a a行。

然后就用 T T T左乘初始矩阵矩阵
[ 0 0 . . . 0 ( n 个 0 ) 1 ] \begin{bmatrix} 0\\ 0\\ ...\\ 0(n个0)\\ 1 \end{bmatrix} 00...0(n0)1
然后输出乘完的结果即珂。
代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
namespace Flandle_Scarlet
{
    #define int long long
    class Matrix//square matrix
    {
        #define N 110//changeable
        private:
            int a[N][N];
        public:
            //variable list
            int n;//size
            //initialization
            Matrix()
            {
                memset(a,0,sizeof(a));
                n=0;
            }
            Matrix(int _n)
            {
                memset(a,0,sizeof(a));
                n=_n;
            }
            Matrix(int _n,int _x)
            {
                n=_n;
                for(int i=0;i<N;++i)
                {
                    for(int j=0;j<N;++j)
                    {
                        a[i][j]=_x;
                    }
                }
            }

            //get value
            int* operator[](int i)
            {
                return *(a+i);
            }

            //set value
            void Set(int x)
            {
                for(int i=0;i<N;++i)
                {
                    for(int j=0;j<N;++j)
                    {
                        a[i][j]=x;
                    }
                }
            }
            void Identity()
            {
                memset(a,0,sizeof(a));
                for(int i=0;i<N;++i)
                {
                    a[i][i]=1;
                }
            }
            #undef N //110
    };
    Matrix operator*(Matrix x,Matrix y)
    {
        Matrix ans(x.n,0);
        int n=ans.n;
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
            {
                if (x[i][j])
                {
                    for(int k=1;k<=n;++k)
                    {
                        ans[i][k]+=x[i][j]*y[j][k];
                    }
                }
            }
        }
        return ans;
    }
    Matrix operator^(Matrix x,int p)
    {
        Matrix ans(x.n,1);
        ans.Identity();
        while(p)
        {
            if (p&1) ans=ans*x;
            x=x*x,p>>=1;
        }
        return ans;
    }

    int n,m,k;
    Matrix Trans(105,0);
    void Lineswap(int a,int b)
    {
        for(int i=1;i<=n+1;++i)
        {
            swap(Trans[a][i],Trans[b][i]);
        }
    }
    void Lineadd(int a)
    {
        ++Trans[a][n+1];
    }
    void Linecls(int a)
    {
        for(int i=1;i<=n+1;++i)
        {
            Trans[a][i]=0;
        }
    }
    void Soviet()
    {
        Trans.Set(0);
        Trans.Identity();
        for(int i=1;i<=k;++i)
        {
            char c[4];scanf("%s",c);
            if (c[0]=='g')
            {
                int a;scanf("%lld",&a);
                Lineadd(a);
            }
            if (c[0]=='s')
            {
                int a,b;scanf("%lld%lld",&a,&b);
                Lineswap(a,b);
            }
            if (c[0]=='e')
            {
                int a;scanf("%lld",&a);
                Linecls(a);
            }
        }
        Matrix Init(n+1,0);
        Init[n+1][1]=1;
        Init=(Trans^m)*Init;
        for(int i=1;i<=n;++i)
        {
            printf("%lld ",Init[i][1]);
        }putchar('\n');
    }

    void IsMyWife()
    {
        if (0)
        {
            freopen("","r",stdin);
            freopen("","w",stdout);
        }
        while(scanf("%lld%lld%lld",&n,&m,&k) and n+m+k)
        {
            Soviet();
        }
    }
    #undef int //long long
};
int main()
{
    Flandle_Scarlet::IsMyWife();
    return 0;
}

回到总题解界面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值