构造矩阵+矩阵快速幂 POJ3735

来源:互联网 发布:使命召唤14优化怎么样 编辑:程序博客网 时间:2024/05/21 13:08

https://vjudge.net/contest/182427#problem/C

这题题意如下,有n 只猫咪,三种关于花生的命令 ( 得花生,吃花生,交换花生 ) ,给出一套命令,重复 n 次,问最后每只猫咪得到多少花生。
M那么大,毫无疑问,矩阵快速幂。

先构造一个单位矩阵,因为只需在单位矩阵上进行操作,然后用操作完之后得到的矩阵乘以初始的状态就得到最终的状态。
看下图:

这里写图片描述

第 i 只猫咪得花生就是在矩阵的第 i 行的最后一列加上1;
注意:如果是 n 只猫咪的话,要用n+1维的矩阵,即n+1维的方阵,多出来的一个才能起到操作的作用!

下面是重点,就是矩阵的快速幂,思路和整数的快速幂一样,不过该过程中会用稀疏矩阵出现,故可借此优化,即跳过0元素;

代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<string>#define ll long longusing namespace std;ll n,m,k;struct matrix{    ll a[120][120];} init;matrix multi(matrix x,matrix y){    matrix ans;    memset(ans.a,0,sizeof(ans.a));    for(int i=0; i<=n; i++)//减少运算量的矩阵乘法,如果为零就不用相乘    {        for(int k=0; k<=n; k++)        {            if(x.a[i][k])            {                for(int j=0; j<=n; j++)                    ans.a[i][j]+=x.a[i][k]*y.a[k][j];            }        }    }    return ans;}matrix mq(ll m)//矩阵快速幂{    if(m==1)        return init;    matrix ans;    memset(ans.a,0,sizeof(ans.a));//这里必须要初始化,不然会wrong    for(int i=0;i<=n;i++)            ans.a[i][i]=1;    while(m)    {        if(m&1)ans=multi(ans,init);        m>>=1;        init=multi(init,init);    }    return ans;}int main(){    char c[10];    int x,y;    while(~scanf("%lld%lld%lld",&n,&m,&k),n+m+k)    {        memset(init.a,0,sizeof(init.a));        for(int i=0; i<=n; i++)            init.a[i][i]=1;        for(int i=0; i<k; i++)        {            scanf("%s",c);            if(c[0]=='g')            {                scanf("%d",&x);                init.a[x-1][n]++;            }            else if(c[0]=='e')            {                scanf("%d",&x);                for(int j=0; j<=n; j++)                    init.a[x-1][j]=0;            }            else            {                scanf("%d %d",&x,&y);                for(int j=0; j<=n; j++)                    swap(init.a[x-1][j],init.a[y-1][j]);            }        }        matrix ans=mq(m);        for(int i=0; i<n-1; i++)            printf("%lld ",ans.a[i][n]);        printf("%lld\n",ans.a[n-1][n]);    }}