• 矩阵快速幂求fib


    链接:https://www.nowcoder.com/acm/contest/189/D
    来源:牛客网

    题目描述

    qn是个特别可爱的小哥哥,qy是个特别好的小姐姐,他们两个是一对好朋友 [ cp (划掉~)
    又是一年嘤花烂漫时,小qn于是就邀请了qy去嘤花盛开的地方去玩。当qy和qn来到了田野里时,qy惊奇的发现,嘤花花瓣以肉眼可见的速度从树上长了出来。
    仔细看看的话,花瓣实际上是以一定规律长出来的,而且,每次张成新的花瓣的时候,上一次的花瓣就会都落到地上,而且不会消失。
    花瓣生长的规律是,当次数大于等于2时,第i次长出来的花瓣个数和上一次张出来的花瓣个数的差是斐波那契数列的第i-1项。初始的时候地上没有花瓣,树上的花瓣个数为1,第一次生长的花瓣个数为1。初始的那个花瓣就落到了地上
    现在,小qn想知道,经过k次生长之后,树上和地上的总花瓣个数是多少?
    ps:斐波那契数列:
        f[1]=f[2]=1;f[i]=f[i-1]+f[i-2] (i>=2且i   N+

    输入描述:

    一行一个数k

    输出描述:

    一行一个数m,表示第k次生长过后,树上和地上的总花瓣数是多少。由于答案会很大,请你将答案mod 998244353后输出
    示例1

    输入

    复制
    4

    输出

    复制
    12

    说明

    第一次:树上1,地上1.第二次树上2,地上1+1,第三次树上3,地上1+1+2,第四次树上5,地上1+1+2+3。总共12个
    示例2

    输入

    复制
    5

    输出

    复制
    20

    说明

    第五次树上8,地上1+1+2+3+5。总共20个

    备注:

    对于0%的数据,有k=样例
    对于20%的数据,有k<=1'000
    对于60%的数据,有k<=1'000'000
    对于80%的数据,有k<=1'000'000'000
    对于100%的数据,有k<1'000'000'000'000'000'000
    题解:本题是求fib的前n项和
    这里有个结论,fib的前n项和=fib(n+2)-1
    但是数据范围。。。。异常大,所以一看,只能矩阵快速幂加速递推了
    先来讲一讲矩阵运算对于一个n*m的矩阵,只有m*p的矩阵才能与其进行乘法,最后乘出来是n*p
    的矩阵,对于一个矩阵a,b

    这道题用矩阵来写是这样的一个操作
    首先我们设f(n)={f[n],f[n+1]},那么f(n-1)={f[n-1],f[n]}
    那么矩阵f(n)的第一项等于矩阵f(n-1)的第二项,矩阵f(n)的第一项等于矩阵f(n-1)的第一项+第二项
    实际上就等于所以,求f(n)就相当于求f(0)*那么用快速幂处理即可
    代码:
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    typedef long long ll;
    
    const ll mod=998244353;
    
    ll f[5];
    ll c[5][5]={{0,0},{0,0,1},{0,1,1}};
    
    void get(){
         ll a[5];
         memset(a,0,sizeof(a));
         for (int i=1;i<=2;i++){
            for (int k=1;k<=2;k++){
                a[i]=(a[i]+f[k]*c[k][i]%mod)%mod;
            }
         }
         f[1]=a[1];
         f[2]=a[2];
    }
    
    void self(){
         ll a[5][5];
         memset(a,0,sizeof(a));
         for (int i=1;i<=2;i++){
            for (int j=1;j<=2;j++){
                for (int k=1;k<=2;k++){
                    a[i][j]=(a[i][j]+c[i][k]*c[k][j]%mod)%mod;
                }
            }
         }
         for (int i=1;i<=2;i++)
            for (int j=1;j<=2;j++) c[i][j]=a[i][j];
    }
    
    int main(){
        f[1]=1;
        f[2]=1;
        ll k;
        scanf("%lld",&k);
        k+=2;
        for (;k;k>>=1){
            if(k&1) get();
            self();
        }
        printf("%lld",f[1]-1);
    return 0;
    }
    
    
    
     
     
  • 相关阅读:
    CSP介绍、以及使用CryptoAPI枚举CSP并获取其属性
    Data Binding Guide——google官方文档翻译(下)
    ZOJ 3430 Detect the Virus 【AC自动机+解码】
    Visual Studio 中 Tab 转换为空格的设置
    梭子鱼:APT攻击是一盘更大的棋吗?
    APT攻击将向云计算平台聚焦
    【转】ubuntu修改IP地址和网关的方法
    程序员谈学习:我为什么要学习Linux?
    VS2010 快捷键
    Visual Assist X 10.6.1837完美破解版(带VS2010破解)
  • 原文地址:https://www.cnblogs.com/lmjer/p/9642476.html
Copyright © 2020-2023  润新知