[caioj 1483,利用矩阵乘法解决的经典题目五]成群的细菌

n个培养皿排成一个圈,每个里面都有一些细菌。培养皿逆时针编号为1,2,…,n,第i个培养皿里有a[i]个细菌。细菌不停地活动着,它们有可能会进行六种操作:
d i 0,表示第i个培养皿的所有细菌都死亡。
r i k,表示第i个培养皿的每个细菌分裂成k个。
c i j,表示把第j个培养皿的所有细菌复制到第i个培养皿。
t i j,表示把第j个培养皿的所有细菌转移到第i个培养皿。
s i j,表示交换第i和第j两个培养皿的细菌。
m 0 0,表示每个培养皿的细菌都同时转移到它逆时针的下一个培养皿。
一旦某个培养皿里有超过s个细菌,每s个细菌会合在一起进化成一个高级组织而脱离培养皿,这些细菌重复的执行着m条命令(编号为1,2,…,m),即第X时刻执行第X mod m条命令。问在第t时刻执行命令后,每个培养皿各有多少个细菌?已知初始的时候每个培养皿恰好有一个细菌。

这道题是矩阵乘法加上快速幂,跟vijos 1049思路差不多,都是把所有的操作转为矩阵,然后乘在一起,变成一个半成品结果矩阵,之后这个半成品结果矩阵要平方t/m次(需要快速幂),不过,可能会有余数,所以剩下的要再单独模拟,最后,结果矩阵就诞生了,再用它乘初始序列(都为1),这道题就解决了。两题最大的区别就是矩阵构造来说,这道题复杂了一点。
(一开始都为单位矩阵,i,j,k与输入意思一样,看上面)
d操作:矩阵中的a[i][i]=0;
r操作:矩阵中的a[i][i]=k;
c操作:矩阵中的a[i][j]=1;
t操作:矩阵中的a[i][j]=1,a[j][j]=0;
s操作:矩阵中的a[i][i]=a[j][j]=0,a[i][j]=a[j][i]=1;
m操作:矩阵中的最后一行放到最上面;

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,he;
struct node
{
    long long a[110][110];
    node()
    {
        memset(a,0,sizeof(a));
    }
}pre[25];
node chengfa1(node a,node b)
{
    node c;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=1;k<=n;k++)
            {
                c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%he;
            }
        }
    }
    return c;
}
node chengfa2(node a,node b)
{
    node c;
    for(int i=1;i<=n;i++)
    {
        for(int k=1;k<=n;k++)
        {
            c.a[i][1]=(c.a[i][1]+a.a[i][k]*b.a[k][1])%he;
        }
    }
    return c;
}
int main()
{
    int m,t;
    char s[110];
    node f,ans,ss;
    scanf("%d%d%d%d",&n,&m,&t,&he);
    for(int i=1;i<=n;i++)
    {
        f.a[i][1]=1;ans.a[i][i]=ss.a[i][i]=1;
        for(int j=1;j<=m;j++)pre[j].a[i][i]=1;
    }
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%s%d%d",s+1,&x,&y);
        if(s[1]=='d')pre[i].a[x][x]=0;
        if(s[1]=='r')pre[i].a[x][x]=y;
        if(s[1]=='c')pre[i].a[x][y]=1;
        if(s[1]=='t'){pre[i].a[x][y]=1;pre[i].a[y][y]=0;}
        if(s[1]=='s')
        {
            pre[i].a[x][x]=pre[i].a[y][y]=0;
            pre[i].a[x][y]=1;pre[i].a[y][x]=1;
        }
        if(s[1]=='m')
        {
            pre[i].a[1][1]=0;pre[i].a[1][n]=1;
            for(int j=2;j<=n;j++)
            {
                pre[i].a[j][j]=0;pre[i].a[j][j-1]=1;
            }
        }
    }
    for(int i=1;i<=m;i++)ss=chengfa1(pre[i],ss);
    int x=t/m;
    if(x==1)ans=ss;
    else
    {
        while(x>0)
        {
            if(x%2==1)ans=chengfa1(ss,ans);
            ss=chengfa1(ss,ss);
            x/=2;
        }
    }
    if(t%m!=0)
    {
        for(int i=1;i<=(t-t/m*m);i++)ans=chengfa1(pre[i],ans);
    }
    f=chengfa2(ans,f);
    for(int i=1;i<n;i++)printf("%lld ",f.a[i][1]);
    printf("%lld\n",f.a[n][1]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
递归成群的奶牛是一个C语言编程项目,它包含了多个经典的递归应用代码,如斐波那契数列递归解法、汉诺塔递归算法、全排列递归算法、八皇后递归算法等。这些代码都是通过递归的方式实现的,递归是一种非常重要的编程技巧,它可以让程序更加简洁、优雅、易于理解和维护。 下面是递归成群的奶牛中包含的一些经典递归算法的简要介绍: 1. 斐波那契数列递归解法:斐波那契数列是一个非常经典的数列,它的前两项为0和1,后面每一项都是前两项之和。递归解法是通过递归调用函数来实现的,但是由于递归的效率较低,所以在实际应用中一般采用迭代的方式来实现。 2. 汉诺塔递归算法:汉诺塔是一个经典的数学问题,它的目标是将一堆盘子从一个柱子移动到另一个柱子,每次只能移动一个盘子,并且大盘子不能放在小盘子上面。递归算法是通过递归调用函数来实现的,它的思路是将问题分解为若干个子问题,然后递归地解决每个子问题。 3. 全排列递归算法:全排列是指将一组数按照一定的顺序进行排列,递归算法是通过递归调用函数来实现的,它的思路是将问题分解为若干个子问题,然后递归地解决每个子问题。 4. 八皇后递归算法:八皇后问题是一个经典的数学问题,它的目标是在一个8x8的棋盘上放置8个皇后,使得每个皇后都不会互相攻击。递归算法是通过递归调用函数来实现的,它的思路是将问题分解为若干个子问题,然后递归地解决每个子问题。 5. 递归的测试代码:递归的测试代码是一个用于测试递归算法的程序,它可以帮助程序员检查递归算法的正确性和效率。 6. 求字符串长度的递归算法:求字符串长度是一个非常基本的问题,递归算法是通过递归调用函数来实现的,它的思路是将字符串分解为若干个子问题,然后递归地解决每个子问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值