• luogu P1962 斐波那契数列


    (gg直接讲的用矩阵求斐波那契数列

    (原地死亡

    (全程一脸懵逼

    (然后看了半个点题解

    首先,什么是矩阵呢

    就是类似于这样的东西(里面可以填什么复数啊,实数啊的

    然后矩阵的基本运算了解一下

    加法很简单emmmm(不说了

    乘法需要了解一下,毕竟比较神奇

    A * B != B * A 难道不觉得违背常识吗?多神奇啊!

    (我觉得讲矩阵乘法讲的最好,最通俗易懂的是曹天元所著的《上帝掷骰子吗》中 chapter 05 part 3,推荐看一下

    矩阵乘法嘛。。。只要知道基本要求就那么求就行了emmmm

    两个矩阵,第一个矩阵的列数与第二个矩阵的行数相等时即可相乘

    举个栗子

    然后正经的解释和公式是酱的:

    设A为 m * p 的矩阵,B为 p * n 的矩阵,那么称 m * n 的矩阵C为矩阵A与B的乘积,记作 C = AB

    其中矩阵C中的第 i 行第 j 列元素可以表示为

    需要注意的是

    矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。
    乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。

    (来源百度百科【特别鸣谢orz

    大概理解了矩阵乘法之后我们来看看这道题吧

    标签是矩阵乘法诶那怎么用呢【考场上能想到矩阵乘法的都tql!!!

    一看数据范围,显然正常递推会只得60分

    如果想要拿到满分需要想一下优化

    然后我们刚刚说到矩阵

    (我也不知道他们怎么想出来用矩阵的 tql!!!

    我们会发现矩阵的定义里有这么一个东西叫做单位矩阵

    主对角线上的元素都为1,其余元素全为0的n阶矩阵称为n阶单位矩阵

    (主对角线就是左上角到右下角的那条对角线

    它长这个样子

    它有什么用呢?

    所有矩阵乘上单位矩阵都等于本身

    哇看起来好鸡肋23333

    说实话我也不知道它有什么用

    (但是它给我们提供了一个思路,如何模拟斐波那契数列

     如果我们构造一个矩阵(符合斐波那契数列的规律

    我们要推出它从何而来

    因为我们知道 F [i] = F [i - 1] + F [i - 2]

    那么某两个矩阵相乘能够得到这样一个矩阵

     

    因为我们要找规律嘛,所以其中一个矩阵一定与构造的那个矩阵性质相似

    即为 

    那再逆着推出来另一个矩阵就很简单了

    最后得到

    这样一直推下去

    一定会推到 i = 2 ,i - 1 = 1 

    这样的话定义一个初始矩阵两行全为一,再反复乘这个固定的

    矩阵

    就能得到最终的结果

    因为最初的 F [1],F [2]已经定义了

    所以要求出F [n]的值,我们只需要乘上固定矩阵的 n - 2次方即可

    这里需要用到矩阵快速幂

    其实和快速幂没什么区别,只是需要写一个矩阵相乘的函数或是重置运算符

    但是一定要记住,因为矩阵相乘 A * B != B * A

    所以如果初始矩阵与固定矩阵乘反了的话,结果就不一样了

    如果反过来,初始矩阵就应该是一行两列的矩阵了

    (我就是这样写的23333

    最后的结果就是第一行第一列的数了

    看代码吧~

    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define mod 1000000007//别忘了膜
    using namespace std;
    
    struct matrix {
        ll a[3][3];
        matrix() {
            memset(a,0,sizeof(a));
        }
    } ans,base;//用结构体存放矩阵,并在结构体中将数组一次性初始化
    
    matrix operator * (const matrix &x,const matrix &y) {
        matrix z;
        for(ll i = 1; i <= 2; i++)
            for(ll j = 1; j <= 2; j++)
                for(ll k = 1; k <= 2; k++)
                    z.a[i][j] = (z.a[i][j] + x.a[i][k] * y.a[k][j] % mod) % mod;
        return z;
    }//重置运算符,不然写个函数也行
    
    void quickpow(ll b) {
        while(b) {
            if(b & 1) ans = ans * base;//别乘反了
            base = base * base;
            b >>= 1;
        }
    }//快速幂
    
    int main() {
        ll n;
        scanf("%lld",&n);
        if(n <= 2) {
            printf("1");
            return 0;
        }
        base.a[1][1] = base.a[1][2] = base.a[2][1] = 1;//固定矩阵
        ans.a[1][1] = ans.a[1][2] = 1;//初始矩阵
        quickpow(n - 2);
        printf("%lld",ans.a[1][1] % mod);
        return 0;
    }

    emmmmm

    那么这道题就讲完啦

    第二道蓝题祭~

  • 相关阅读:
    涂鸦
    触发事件续
    触摸事件基本介绍
    背景平铺
    屏幕截图
    图片的裁剪
    图片水印
    UIKit绘图方法
    Java范型学习笔记
    《Head first设计模式》学习笔记
  • 原文地址:https://www.cnblogs.com/sevenyuanluo/p/10041378.html
Copyright © 2020-2023  润新知