POJ 3233

这个题,一开始就没想到竟然可以拿子矩阵的样子进行呈现,作为一个曾经数学系的孩子来说真的是还惭愧了。还搞了半天了。唉,这个题的看到还有递归的写法,先说说正常的快速幂的写法,这里在网上看到两种矩阵的递推式子


这个是第一种推导方法也就是我的做法,只需要最后在右上角的矩阵再减去一个E就可以饿。其间的可以用快速幂来求解。

然后就是第二种推导方法


这是第二种推导方法,也是可见明显可以得出答案的。

然后就是第二种递归的写法了,这个没怎么想到


同样这个递归也是很好写的,难的就是这个递推的式子不好搞定,想不出来就没法做了。

还有前面的两种矩阵的方式写法,实际上也是难在了矩阵的构造上了,如果构造出来,还是好解决的。

这里可以的出一点经验的就是其实一般的都是一个数的k次幂,然后我们借用矩阵幂来构造矩阵优化解决,当需要求的是矩阵的时候,实际上可以把矩阵看成一个数字,然后构造矩阵的矩阵来解决问题,也就是把原来矩阵看成构造后的子矩阵的方式来解决问题。

那么实际上如果是这个问题:

•eg.求S(n)=sigma(i^k)(n<10^9,k<100)
•结果对10^9+7取模
那么这个地方也就是要构造一个矩阵就可以,如下所示:





最后贴上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;

int n,k,m;
struct Mat
{
    int mat[100][100];
};
Mat a;

Mat operator * (Mat a, Mat b) {
    Mat mm;
    memset(mm.mat, 0, sizeof(mm.mat));
    int i, j, k;
        for(i = 0; i < 2*n; ++i) {
           // if(a.mat[i][k] <= 0)  continue;    //***
            for(j = 0; j < 2*n; ++j) {
               // if(b.mat[k][j] <= 0)    continue;    //***
               for(k=0;k<2*n;++k)
                {
                    mm.mat[i][j] =(mm.mat[i][j]+(a.mat[i][k] * b.mat[k][j])%m)%m;
                }
            }
        }
    return mm;
}

Mat operator ^ (Mat a, int k) {
    Mat m,s;
    memset(s.mat,0,sizeof(s.mat));
    int i,j;
    for(i = 0; i < 2*n; ++i)
        for(j = 0; j < 2*n; ++j)
            m.mat[i][j] = (i == j);
    for( k++; k; k>>=1) {
        if(k&1) m = m*a;
         a=a*a;
    }
    return m;
}

int main()
{
   while(scanf("%d%d%d",&n,&k,&m)==3)
   {
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
            scanf("%d",&a.mat[i][j]);
    }

    for(int i=0;i<n;i++)
    {
        a.mat[i+n][i+n]=a.mat[i][i+n]=1;
    }

    Mat sum=a^k;
    for(int i=0;i<n;i++)
    {
      sum.mat[i][i+n]--;
    }
     for(int i=0;i<n;i++)
     {
         for(int j=n;j<2*n;j++)
         {
             if(j==n)
             printf("%d",sum.mat[i][j]%m);
             else
                printf(" %d",sum.mat[i][j]%m);
         }
         puts("");
     }
   }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值