zoukankan      html  css  js  c++  java
  • 斐波那契数列小结

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

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

    基础问题

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

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

    显然最多处理到1e7

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

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

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

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

    $$ left [ egin{matrix} 1 & 1 \ 1 & 0  end{matrix} ight] ag{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;
    }
    

      

  • 相关阅读:
    Apache Tomcat的安装与配置
    2007年东软校园招聘笔试题(山东大学)
    成功修复U盘,狂喜中~哈哈哈!!!
    检测和修复U盘的一般过程(一、软检测篇)
    在 hp3172宽屏笔记本上安装windowsXP+solaris10 双系统(1)--环境准备篇
    递归法查找假硬币
    把ppt转换为word的一段脚本
    2007年11月神州数码软件工程师(网络公司)招聘笔试题目
    不能正常使用oracle的解决办法(Oracle10g Express 版)
    光驱弹不出来怎么办?光驱弹不出来的简易解决办法。
  • 原文地址:https://www.cnblogs.com/logeadd/p/9397856.html
Copyright © 2011-2022 走看看