[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章