斐波那契数列小结

关于斐波那契数列,相信大家对它并不陌生,关于其的题目也不在少数。

我现在总结一下有关它的一些有趣的性质。

基础问题

1.求斐波那契数列的第k项

常规方法是利用f[i]=f[i-1]+f[i-2],时间复杂度为O(n)

显然最多处理到1e7

假如n到1e18怎么办,O(n)显然就T飞了.

我们考虑利用什么方法来加速

斐波那契数列数列是其次线性递推式

所以是可以利用矩阵乘法进行求解的

$$ \left [ \begin{matrix} 1 & 1 \\ 1 & 0  \end{matrix} \right] \tag{2}  $$

很显然用[Fi,F(i-1)]乘以上面的矩阵是可以得到[Fi+F(i-1),Fi]

这样,再利用矩阵快速幂就可以做到8logn求解斐波那契数列第n项了

2.斐波那契数列公约数

求Fi与Fj的最大公约数

这里要用到一个神奇的性质

gcd(F[n],F[m])=F[gcd(n,m)]

证明:丢链就跑

这里的结论可以记下来,可能会有用

3.斐波那契数列的循环节

提交地址

求斐波那契数列modn的

根据一些奇奇怪怪的性质,我们可以在logp的时间求斐波那契数列的循环节

综合问题

洛谷4000

求一个循环节,然后矩阵快速幂,就是一个模板的合集

// luogu-judger-enable-o2
# include<cstring>
# include<iostream>
# include<cstdio>
# include<cmath>
# include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
ll dp[maxn*10];
ll prime[maxn],s=0;
bool vis[maxn];
char ch[30000005];
int len;
void init_prime()
{
    for(ll i=2;i<maxn;i++)
    {
        if(!vis[i]) prime[s++]=i;
        for (ll j=0;j<s&&i*prime[j]<maxn;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
    return;
}
ll pow_mod(ll a1,ll b1)
{
    ll ans=1;
    while(b1)
    {
        if(b1&1) ans=ans*a1;
        b1>>=1;
        a1*=a1;
    }
    return ans;
}
ll pow_mod2(ll a,ll b,ll p)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%p;
        b>>=1;
        a=a*a%p;
    }
    return ans;
}
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
bool f(ll n,ll p)
{
    return pow_mod2(n,(p-1)>>1,p)==1;
}
struct matrix
{
    ll x1,x2,x3,x4;
};
    matrix matrix_a,matrix_b,matrix_c;
matrix M2(matrix aa,matrix bb,ll mod)
{
    matrix tmp;
    tmp.x1=(aa.x1*bb.x1%mod+aa.x2*bb.x3%mod)%mod;
    tmp.x2=(aa.x1*bb.x2%mod+aa.x2*bb.x4%mod)%mod;
    tmp.x3=(aa.x3*bb.x1%mod+aa.x4*bb.x3%mod)%mod;
    tmp.x4=(aa.x3*bb.x2%mod+aa.x4*bb.x4%mod)%mod;
    return tmp;
}
matrix M(ll n,ll mod)
{
    matrix a,b;
    a=matrix_a;b=matrix_b;
    while(n){
        if(n&1){
            b=M2(b,a,mod);
        }
        n>>=1;
        a=M2(a,a,mod);
    }
    return b;
}
    ll fac[100][2],l,x,fs[1000];
void dfs(ll count,ll step)
{
    if(step==l)
    {
        fs[x++]=count;
        return ;
    }
    ll sum=1;
    for(ll i=0;i<fac[step][1];i++)
    {
        sum*=fac[step][0];
        dfs(count*sum,step+1);
    }
    dfs(count,step+1);
}
ll solve2(ll p)
{
    if(p<1e6&&dp[p]) return dp[p];
    bool ok=f(5,p);
    ll t;
    if(ok) t=p-1;
    else t=2*p+2;
    l=0;
    for(ll i=0;i<s;i++)
    {
        if(prime[i]>t/prime[i]) break;
        if(t%prime[i]==0)
        {
            ll count=0;
            fac[l][0]=prime[i];
            while(t%prime[i]==0)
            {
                count++;t/=prime[i];
            }
            fac[l++][1]=count;
        }
    }
    if(t>1)
    {
        fac[l][0]=t;
        fac[l++][1]=1;
    }
    x=0;
    dfs(1,0);
    sort(fs,fs+x);
    for(ll i=0;i<x;i++)
    {
        matrix m1=M(fs[i],p);
        if(m1.x1==m1.x4&&m1.x1==1&&m1.x2==m1.x3&&m1.x2==0)
        {
            if(p<1e6) dp[p]=fs[i];
            return fs[i];
        }
    }
}
ll solve(ll n){
    ll ans=1,cnt;
    for(ll i=0;i<s;i++){
        if(prime[i]>n/prime[i]){
            break;
        }
        if(n%prime[i]==0){
            ll count=0;
            while(n%prime[i]==0){
                count++;n/=prime[i];
            }
            cnt=pow_mod(prime[i],count-1);
            cnt*=solve2(prime[i]);
            ans=(ans/gcd(ans,cnt))*cnt;
        }
    }
    if(n>1){
        cnt=1;
        cnt*=solve2(n);
        ans=ans/gcd(ans,cnt)*cnt;
    }
    return ans;
}
void pre()
{
    init_prime();
    matrix_a.x1=matrix_a.x2=matrix_a.x3=1;
    matrix_a.x4=0;
    matrix_b.x1=matrix_b.x4=1;
    matrix_b.x2=matrix_b.x3=0;
    dp[2]=3;dp[3]=8;dp[5]=20;
}
int main(){
    ll t,n,MOD,num=0;
    pre();
    scanf("%s",ch+1);
    len=strlen(ch+1);
    scanf("%lld",&n);
    MOD=solve(n);
    for (int i=1;i<=len;i++)
    {
        num=num*10+ch[i]-‘0‘;
        while (num>=MOD) num-=MOD;
    }
    matrix_c=M(num,n);
    printf("%lld",matrix_c.x2);
    return 0;
}

  

原文地址:https://www.cnblogs.com/logeadd/p/9397856.html

时间: 2024-10-03 22:41:02

斐波那契数列小结的相关文章

关于斐波那契数列的一点小结

斐波那契数列就是0,1,1,2,3,5……这样的一波数列,第三个数是前两个数的和. 兔子问题,上楼梯的台阶方法的个数问题,都是斐波那契数列. 斐波那契可以简单的用递归实现: 1 def fib(n) 2 # Calculate the nth Fibonacci Number 3 return n if n == 0 || n == 1 4 return fib(n-1) + fib(n-2) 5 end 简单有效,但是在n很大的时候时间长. 也可以用迭代来实现 1 def fib(n) 2 r

leetcode笔记:Climbing Stairs(斐波那契数列问题)

一.题目描述 You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? 题目的大意是,已知有n阶楼梯,每次只能爬1阶或2阶楼梯,问爬到第n阶楼梯共有几种爬法-_-||.题目可以看成是,设f(n)表示爬到第n 阶楼梯的方法数,为

用递归和非递归的方法输出斐波那契数列的第n个元素(C语言实现)

费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数.斐波那契数列.费氏数列.黄金分割数列. 在数学上,费波那契数列是以递归的方法来定义: {\displaystyle F_{0}=0} {\displaystyle F_{1}=1} {\displaystyle F_{n}=F_{n-1}+F_{n-2}}(n≧2) 用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出.首几个费波那契系数是: 0, 1, 1, 2, 3

Fibonacci斐波拉契数列----------动态规划DP

n==10 20 30 40 50 46 体验一下,感受一下,运行时间 #include <stdio.h>int fib(int n){ if (n<=1)     return 1; else            return fib(n-1)+fib(n-2); }int main( ){ int n; scanf("%d",&n); printf("%d\n" ,fib(n) );} 先 n==10 20 30 40 50 46

《剑指Offer》题目——斐波拉契数列

题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项.(n<=39) 题目分析:如果使用简单的递归,很容易造成栈溢出.采用递推的方式即可. 代码: public class Fibonacci { public static int fibonacci(int n){ int res[] = new int[2]; res[0]=1; res[1]=1; int temp = 0; if(n==0) return 0; if(n<=2) return res[

js算法集合(二) javascript实现斐波那契数列 (兔子数列) Javascript实现杨辉三角

js算法集合(二)  斐波那契数列.杨辉三角 ★ 上一次我跟大家分享一下做水仙花数的算法的思路,并对其扩展到自幂数的算法,这次,我们来对斐波那契数列和杨辉三角进行研究,来加深对Javascript的理解. 一.Javascript实现斐波那契数列 ①要用Javascript实现斐波那契数列,我们首先要了解什么是斐波那契数列:斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为

斐波那契数列

前几天学了javascript,挺难的比之前学的H5难多了,之前还觉得H5很难,一比较之下就相形见绌了. 在JS里面代码什么的还是蛮简单的,就是逻辑问题让你绕不过来....在这些逻辑问题里又有一个既难而且十分经典的问题,那就是斐波那契数列. 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列",指的是这样一个数列:1.1.2.3.5.8.13.21.34

斐波那契数列(分析别人的代码)

斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........ 这个数列从第3项开始,每一项都等于前两项之和. n1 = 0 #给n1赋初始值 n2 = 1 #给n1赋初始值 count = 0 #给计数器初始值 while count < 10: #循环条件为计数器小于10 nth = n1 + n2 #n

快速求斐波那契数列(矩阵乘法+快速幂)

斐波那契数列 给你一个n:f(n)=f(n-1)+f(n-2) 请求出 f(f(n)),由于结果很大请 对答案 mod 10^9+7; 1<=n<=10^100; 用矩阵乘法+快速幂求斐波那契数列是经典应用: 矩阵公式 C i j=C i k *C k j; 根据递推式 构造2*2矩阵: 原始矩阵 1 0 0 1 矩阵 2 1 1 1 0 原始矩阵与矩阵 2相乘达到转化状态效果: 对矩阵二进行快速幂 乘法:达到快速转化矩阵的效果: 即使达到快速转化状态:那么大的数据范围也很难求解: 高精?这有