POJ 3735 Training little cats(矩阵快速幂)

本文介绍了一种通过矩阵运算解决猫与花生数量变化的问题。具体地,文章提出了一种利用矩阵快速幂的方法来高效计算经过多次操作后每只猫所拥有的花生数量。这种方法不仅简化了计算过程,还提高了计算效率。

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

Description
有n只猫,开始时每只猫都没有花生,三种操作
g x:给第x只猫一个花生
e x:第x只猫把它所拥有的花生都吃完
s x y:第x只猫与第y只猫交换所拥有的所有花生
现在给出k中操作以及循环数m,问在进行了m次这k次操作后每只猫分别有多少个花生
Input
多组输入u,每组用例第一行为三个整数n,m,k分别表示猫数,操作循环数以及操作数,之后k行每行一个操作,以0 0 0结束输入
Output
对于每组用例,输出m轮k次操作后每只猫所拥有的花生数
Sample Input
3 1 6
g 1
g 2
g 2
s 1 2
g 3
e 2
0 0 0
Sample Output
2 0 1
Solution
将每只猫的花生数放在一个1*n的矩阵中,考虑用k次操作构造成一个n*n矩阵A,因为三种操作中存在某种猫的花生数加一的操作,所以要把矩阵扩展一位放1,即[1,cnt1,cnt2,…,cntn],初始化矩阵A为单位矩阵,对于操作1,要把A[0][x]++;对于操作2,要令A[i][x]=0;对于操作3,要swap(A[i][x],A[i][y]),构造出A矩阵之后用矩阵快速幂求出A^m后第一行元素即为操作后每只猫的花生数
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 111
typedef long long ll;
struct Mat
{
    ll mat[maxn][maxn];//矩阵 
    ll row,col;//矩阵行列数 
};
Mat mod_mul(Mat a,Mat b)//矩阵乘法 
{
    Mat ans;
    ans.row=a.row;
    ans.col=b.col;
    memset(ans.mat,0,sizeof(ans.mat));
    for(ll i=0;i<ans.row;i++)       
        for(ll k=0;k<a.col;k++)
            if(a.mat[i][k])
                for(ll j=0;j<ans.col;j++)
                    ans.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
    return ans;
}
Mat mod_pow(Mat a,ll k)//矩阵快速幂 
{
    Mat ans;
    ans.row=a.row;
    ans.col=a.col;
    for(ll i=0;i<a.row;i++)
        for(ll j=0;j<a.col;j++)
            ans.mat[i][j]=(i==j);
    while(k)
    {
        if(k&1)ans=mod_mul(ans,a);
        a=mod_mul(a,a);
        k>>=1;
    }
    return ans;
}
int main()
{
    ll n,m,k;
    while(scanf("%lld%lld%lld",&n,&m,&k),n||m||k)
    {
        Mat ans;//初始化一个(n+1)*(n+1)的单位矩阵 
        ans.row=ans.col=n+1;
        for(ll i=0;i<ans.row;i++)
            for(ll j=0;j<ans.col;j++)
                ans.mat[i][j]=(i==j);
        while(k--)
        {
            char op[3];
            ll x,y;
            scanf("%s",op);
            if(op[0]=='g')
            {
                scanf("%lld",&x);
                ans.mat[0][x]++;
            }
            else if(op[0]=='e')
            {
                scanf("%lld",&x);
                for(ll i=0;i<=n;i++)
                    ans.mat[i][x]=0;
            }
            else if(op[0]=='s')
            {
                scanf("%lld%lld",&x,&y);
                for(ll i=0;i<=n;i++)
                    swap(ans.mat[i][x],ans.mat[i][y]);
            }
        }
        ans=mod_pow(ans,m);
        for(ll i=1;i<=n;i++)
            printf("%lld%c",ans.mat[0][i],i==n?'\n':' ');
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值