蓝桥杯2014年第五届真题——斐波那契(矩阵快速幂)

蓝桥杯2014年第五届真题——斐波那契(矩阵快速幂)

1.题目描述
2.输入输出
在这里插入图片描述
3.样例输入输出
在这里插入图片描述
4.解题思路
思路一:暴力求解

最常规的思路,一看到斐波那契数列就用递归去写,因此可以写一个斐波那契的函数,然后调用函数来写

#include<bits/stdc++.h>
using namespace std;
int fb(int n){
	if(n==1 || n==2) return 1;
	else return fb(n-1)+fb(n-2);
}
int main(){
	int n,m,p;
	cin>>n>>m>>p;
	long long kount=0;
	for(int i=1;i<=n;i++){
		kount+=fb(i);
	}
	cout<<kount;
	cout<<fb(m);
	cout<<p;
	cout<<(kount%fb(m))%p;
	
	
}

很遗憾,这样做在n非常大的时候会超时。因此如果在蓝桥杯中使用递归暴力去求解这题,只能骗到一部分分数,没办法完全ac掉。

思路二:矩阵快速幂
先了解一下快速幂,所谓快速幂,就是快速的求某一个数的多少次幂,其时间复杂度是O(logn),与朴素的O(n)相比,效率得到了极大的提高,它的基本原理是二进制
快速幂:
对于a^n , n一定可以用二进制表示。
如156(10)=10011100(2)
求解a^156,原来要进行156-1=155次乘法运算,现在的差不多运算次数就是他 二进制的长度二进制中1的个数=84=24次
在这里插入图片描述

快速幂模板函数

long long fastpow(long long x,long long y)
{
    long long a=1;//a为结果
    while(y)
    {
        if(y&1) a=a*x;
        x=x*x;//一个中间转移量. y每右移一次, x 就多一个平方
        y=y>>1;
    }
    return a;
}

矩阵快速幂:
1.相对于一般的快速幂,矩阵快速幂仅仅是把他的底数和乘数换成了矩阵形式,而相应的乘法运算什么的也遵循矩阵的运算法则。
2.矩阵快速幂的难点主要是在关系矩阵的构造上,只要关系矩阵构造出来了,其他的就只是套模板运算而已。

矩阵

struct node {
    int mat[15][15];//定义矩阵 
}x,y;

矩阵乘法

node mul(node x,node y){//矩阵乘法 
    node tmp;
    for(int i=0;i<len;i++){
        for(int j=0;j<len;j++){
            tmp.mat [i][j]=0;
            for(int k=0;k<len;k++){
                tmp.mat [i][j]+=(x.mat [i][k]*y.mat [k][j])%mod;
            }
            tmp.mat [i][j]=tmp.mat[i][j]%mod;
        }
    }
    return tmp;
}

矩阵快速幂

node matpow(node x,node y,int num){//矩阵快速幂 
    while(num){
        if(num&1){
            y=mul(y,x);
        }
        x=mul(x,x);
        num=num>>1;
    }
    return y;
}

斐波那契数列关系矩阵递推式
在这里插入图片描述
本题参考代码(源自网络)

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
LL llmul( LL a,LL b,LL mod ) {
    a%=mod;a+=mod;a%=mod;
    b%=mod;b+=mod;b%=mod;
    if ( a<b )    swap( a,b );
    LL ret=0;
    while ( b ) {
        if ( b&1 )ret=( ret+a )%mod;
        a=( a<<1 )%mod;
        b/=2;
    }
    return ret;
}
struct matrix {
    LL x[3][3];
    matrix() {memset( x,0,sizeof x );}
};
matrix mmul( matrix &A,matrix &B,LL mod ) {
    matrix ret;
    for ( int i=1; i<=2; i++ )
        for ( int j=1; j<=2; j++ )
            for ( int k=1; k<=2; k++ )
            ret.x[i][j]=( ret.x[i][j]+llmul( A.x[i][k],B.x[k][j],mod ) )%mod;
    return ret;
}
matrix E,A;
LL fib( LL n,LL mod ) {
    matrix O=E,B=A;
    while ( n ) {
        if ( n&1 )O=mmul( O,B,mod );
        B=mmul( B,B,mod );
        n/=2;
    }
    return O.x[1][2];
}
LL solve( LL n,LL m,LL mod ) {//f(n)%f(m)%mod
    LL t=n/m;
    //(f(m-1)^t*f(n%m))%f(m)%mod;
    //f(i)^2%f(i-1)=(-1)^(i+1)
    LL p=t/2,q=t%2;
    //{f(m-1)^q*(-1)^(pm)*f(n%m)}%f(m)%mod
    LL fuhao=p*m%2==0?1:-1;
    if ( q==0 ) {
        LL ans=fib( n%m,mod )*fuhao;
        ans%=mod;
        ans+=mod;
        return ans%mod;
    }
    if ( n%m==0 )return 0;
    //f(m-1)*f(n%m)*fuhao%f(m)%mod
    //x%y%mod=(x-a*y)%mod
    //a=[x/y]
    LL x=(llmul(fib(n%m,mod),fib(m-1,mod),mod)*fuhao%mod+mod)%mod;
    LL y=fib(m,mod);
    LL a=fib(n%m-1,mod);
    if(n%m%2==0)    a--;
    if(fuhao<0)    a++;
    a=(a%mod+mod)%mod;
    return ((x-llmul(a,y,mod))%mod+mod)%mod;
}
int main ()
{
    A.x[1][2]=A.x[2][1]=A.x[2][2]=1;
    E.x[1][1]=E.x[2][2]=1;
    LL n,m,mod;
    cin>>n>>m>>mod;
    cout<<( solve( n+2,m,mod )-1+mod )%mod<<endl;//S(n)=f(n+2)-1
    return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chase__young

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值