矩阵快速幂

写个矩阵快速幂的应用吧。
矩阵快速幂主要用来优化一些递推。先动手计算推出题目的递推公式或类似动归的状态转移方程,然后for一遍通常会超时,用矩阵快速幂来优化以做到log2 n的时间复杂度。
先学会矩阵快速幂:就是定义一下矩阵乘法,然后用快速幂即可,注意这里要将原来的1改为单位1(单位矩阵),就是左上到右下对角线是1,剩下是0的矩阵(自己推一下,这样才能保证它乘任何矩阵,原矩阵都不变)。
然后每道题有他的递推式,自己推出,然后构造矩阵。
例题
小澳的坐标系
( coordinate.cpp/c/pas)
【 题目描述】
小澳者表也,数学者景也,表动则景随矣。
小澳不喜欢数学,可数学却待小澳如初恋,小澳睡觉的时候也不放过。
小澳的梦境中出现了一个平面直角坐标系,自原点,向四方无限延伸。
小澳在坐标系的原点,他可以向上、向左或者向右走。他可以走 n 步, 但不
能经过相同的点。
小澳想知道他有多少种走法。
【 输入格式】
输入文件名为 coordinate.in。
输入文件仅第一行一个正整数 n,表示小澳可以走的步数。
【 输出格式】
输出文件名为 coordinate.out。
输出文件共一行,输出一个正整数, 表示答案(对 10^9+7 取模)。
【 输入输出样例 1】
coordinate.in coordinate.out
2 7
【输入输出样例 1 说明】
从(0,0)出发走 2 步,共 7 种走法:
(0,0)->(0,1)->(0,2)
(0,0)->(0,1)->(1,1)
(0,0)->(0,1)->(-1,1)
(0,0)->(1,0)->(2,0)
(0,0)->(1,0)->(1,1)
(0,0)->(-1,0)->(-2,0)
(0,0)->(-1,0)->(-1,1)
【 输入输出样例 2】
coordinate.in coordinate.out
3 17
【 数据规模与约定】
测试点编号 n
1~2 n<=10
3~4 n<=1005~6 n<=1000
7~8 n<=10^6
9~10 n<=10^9

我是推出了 f[i]=a[i]+2*b[i];a[i]=f[i-1];b[i]=a[i-1]+b[i-1];
但经一个哥们指点发现可以合为一个式子:f[i]=2*f[i-1]+f[i-2];实际结果一样,但更简练。于是就按这个写了。没想太清楚前两项咋弄,直接打表,第三项开始算。
构造 【0 1】
【1 2】 矩阵,用它乘【 3 7】,然后可以快速运算。

#include<iostream>
#include<cstdio>
#include<cstring>
#define p 1000000007
using namespace std;

struct mat{
    long long v[2][2];
    mat(){memset(v,0,sizeof(v));}
}ans,a;

int n;

mat c(mat a,mat b)
{
    mat res;
    for(int i=0;i<2;++i)
     for(int j=0;j<2;++j)
      for(int k=0;k<2;++k)
        res.v[i][j]=(res.v[i][j]+(a.v[i][k]*b.v[k][j])%p)%p;
    return res;
}

int main()
{
    freopen("coordinate.in","r",stdin);
    freopen("coordinate.out","w",stdout);
    scanf("%d",&n);
    if(n==1){
        printf("3");
        return 0;
    }
    if(n==2){
        printf("7");
        return 0;
    }
    n-=2;
    ans.v[0][0]=3;ans.v[0][1]=7;
    a.v[0][0]=0;a.v[0][1]=1;
    a.v[1][0]=1;a.v[1][1]=2;
    mat aa;
    aa.v[0][0]=aa.v[1][1]=1;
    aa.v[0][1]=aa.v[1][0]=0;
    while(n>0){
        if(n&1)aa=c(aa,a);
        a=c(a,a);
        n>>=1;
    }
    ans=c(ans,aa);
    printf("%I64d",ans.v[0][1]);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值