矩阵乘法在递推问题中的简单应用

这里我们以Fib问题为例。

Fib数列是一个著名的递推数列,其规律可表示为f[i]=f[i-1]+f[i-2];

我们要做的事,就是求出fib数列的第n项。由于这个数字可能很大,因此只需要输出它对10007取模的结果。
这里我们约定:对于80%的数据,n<10^8。对于100%的数据,n<10^10。

几乎不需要经过多少思考,我们就能写出一个80分版本:

#include <cstdio>
using namespace std;
int main(){
    freopen("fib.in","r",stdin);
    freopen("fib.out","w",stdout); 
    int t,a=1,b=1,c;
    scanf("%d",&t);
    for(t-=2;t>0;--t)
        b+=a, a=b-a, a%=100000000, b%=100000000;
    printf("%d\n",b%10007);
}

然而,仁慈的80分并不能阻止我们的进一步思考。
我们知道,递推的规律可以表示为一个矩阵:{{0,1},{1,1}}

我们采用矩阵乘法的方法,套上qpow的外壳,就形成了以下的100分版本:

#include <cstdio>
using namespace std;
struct martix{
    long long a[2][2];
    martix(){
        a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;
    }
    void getmod(){
        for(int i=0;i<=1;i++)
            for(int j=0;j<=1;j++)
                a[i][j]%=100000000;
        return;
    }
};
martix mui(martix a,martix b){
    martix r;
    for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
            for(int k=0;k<=1;k++)
                r.a[i][j]+=a.a[i][k]*b.a[k][j];
    return r;
}
martix reset(int x,int y,int z,int w){
    martix p;
    p.a[0][0]=x;p.a[0][1]=y;
    p.a[1][0]=z;p.a[1][1]=w;
    return p;
}
int main(){
    freopen("fib.in","r",stdin);
    freopen("fib.out","w",stdout); 
    martix base,result;
    int t;
    scanf("%d",&t);
    base=reset(0,1,1,1);
    result=reset(1,1,1,1);
    t=t>2?t-2:0;
    while(t){
        if(t&1) result=mui(result,base);
        base=mui(base,base);
        base.getmod();
        result.getmod();
        t>>=1;
    }
    printf("%d\n",result.a[1][1]%10007);
}

看起来还真是有点麻烦,不过仔细想想,原理也很简单,只是手指要多费点功夫罢了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值