• 斐波那契和矩阵快速幂


    快速幂

    用于对底数的高次幂求模,例如a32常规运算是a连乘32次,快速幂则计算a2,随后计算a4,a8,a16,a32,只运算了5次,贼快。

    ll power(ll a,ll b,ll q)
    {
        ll res=1;
        while(b)
        {
            if(b%2)
                res=res*a%q;
            b=b/2;
            a=a*a%q;
        }
        return res%q;
    }
    快速幂模板代码

    矩阵快速幂

    1.矩阵相乘

    前者行*后者列。结果矩阵的行列分别是前者行数,后者列数。(既然是幂次方,必然是一个n×n的矩阵)

    例如:矩阵A是n×p的矩阵,矩阵B为p×m的矩阵,这样A和B才能相乘,结果是矩阵C,C的维度是n×m。

    C的计算公式:

    举例说明:

    2.矩阵快速幂和数字快速幂一样,只是每一次矩阵相乘都需要三重循环,看起来挺吓人的,耐心看个5min其实也是能懂的。

    P3390:n阶矩阵快速幂全裸,java只能过90分?(不知道有没有改进的余地,请大佬赐教)

    import java.io.BufferedInputStream;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.Scanner;
    
    public class Main{        //P3390【模板】矩阵快速幂
        
        static long [] [] a=new long [105][105];
        static long [] [] e=new long [105][105];//单位矩阵
        static long p=1000000007;
        static int n;
        static long k;
        public static void main(String []args) {
            //Scanner scan=new Scanner(new BufferedInputStream(System.in));
            Scanner scan=new Scanner( System.in);
            n=scan.nextInt();
            k=scan.nextLong();
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    a[i][j]=scan.nextLong();
            for(int i=1;i<=n;i++)
                e[i][i]=1;
            long [][] ans=pow(a, k);
            for(int i=1;i<=n;i++) {
                for(int j=1;j<=n;j++)
                    System.out.print(ans[i][j]+" ");
                System.out.println();
            }
            
        }
        
        public static long[][] mul(long[][] x,long [][] y){//n阶矩阵相乘
            long [] [] c=new long [105][105];
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    c[i][j]=0;
            //对于c矩阵的结果,是x的列与y的行相乘的结果,使用X的列数作为k,必然对应Y的行
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    for(int k=1;k<=n;k++)
                        c[i][j]=(c[i][j]+x[i][k]*y[k][j])%p;
            return c;
        }
        
        public static long[][] pow(long[][] x,long k ){
            long [] [] res=e;//单位矩阵
            while(k!=0) {
                if(k%2==1)
                    res=mul(res,x);
                x=mul(x, x);
                k=k/2;
            }
            return res;
        }
    }
    P3390 java版
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<math.h>
    #include<string>
    #include<map>
    #include<queue>
    #include<stack>
    #include<set>
    #include<ctime>
    #define ll long long
    #define inf 0x3f3f3f3f
    const double pi=3.1415926;
    using namespace std;
    
    struct matrix{
        ll x[105][105];
    };
    matrix a,e;
    int n;
    ll p=1000000007;
    ll b;
    
    
    matrix mul(matrix a,matrix b){
        matrix res;
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            res.x[i][j]=0;//初始化清0操作
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
              res.x[i][j]=(res.x[i][j]+a.x[i][k]*b.x[k][j]  )%p;
        return res;
    }
    
    matrix pow( matrix a,ll b)
    {
        matrix res=e;
        while(b){
            if(b%2==1)
                res=mul(res,a);
            b=b/2;
            a=mul(a,a);
        }
        return res;
    
    }
    
    
    int main()//P3390
    {
        scanf("%d %lld",&n,&b);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            scanf("%lld",&a.x[i][j]);
        for(int i=1;i<=n;i++)
            e.x[i][i]=1;
    
        matrix ans=pow(a,b);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                printf("%lld ",ans.x[i][j]);
            printf("
    ");
        }
    
        return 0;
    }
    P3390 C++

     斐波那契矩阵快速幂 

    1.斐波那契数列递推式 f(n)=f(n-1)+f(n-2)

    默认第一项为0,f(0)=0;f(1)=1;f(2)=1;f(3)=2;f(4)=3;f(5)=5;f(6)=8;...

    2.融合进矩阵运算公式

    底数矩阵为[  f(2),f(1);f(1),f(0)  ];n次幂后取矩阵An右上角的数为f(n)

    手动验证一下[ 1,1; 1,0 ]*An = [ 1,1; 1,0 ]*[ f(n+1),f(n); f(n),f(n-1) ] = [ f(n+1)+f(n),f(n)+f(n-1); f(n+1),f(n) ] = [ f(n+2),f(n+1); f(n+1),f(n) ];


    斐波那契求前n项平方和

    公式和图证如下:

     

    题目:https://ac.nowcoder.com/acm/contest/3282/A,套用斐波那契矩阵快速幂的模板。

    import java.io.BufferedInputStream;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.Scanner;
    
    public class Main{    
        
        static long[][] a=new long[3][3];//底数矩阵
        static long[][] e=new long[3][3];//单位矩阵
        static long p=1000000007;
        public static void main(String []args) {
            //Scanner scan=new Scanner(new BufferedInputStream(System.in));
            Scanner scan=new Scanner( System.in);
            a[1][1]=1;a[1][2]=1;a[2][1]=1;a[2][2]=0;
            e[1][1]=e[2][2]=1;
            long k=scan.nextLong();
            long[][] res=pow(a, k);
            long ans=res[1][1]*res[1][2]%p;
            System.out.println(ans);
            
        }
        
        public static long[][] mul(long[][] x,long [][] y){//n阶矩阵相乘
            long [] [] c=new long [3][3];
            for(int i=1;i<=2;i++)
                for(int j=1;j<=2;j++)
                    for(int k=1;k<=2;k++)
                        c[i][j]=(c[i][j]+x[i][k]*y[k][j])%p;
            return c;
        }
        public static long[][] pow(long[][] x,long k ){
            long [] [] res=e;//单位矩阵
            while(k!=0) {
                if(k%2==1)
                    res=mul(res,x);
                x=mul(x, x);
                k=k/2;
            }
            return res;
        }
    
    }
    牛客小白20A

    斐波那契循环节

    求斐波那契数列模N意义下的循环节
    1.唯一分解定理
    定义:任何一个数N可以表示成 素数的次方 的乘积
    分解公式: 
    求N的因子个数公式:num=(a1+1)×(a2+1)×......×(an+1);
    2.分别计算Fib数列每个pm的循环节长度,假设长度为L(pm),用L(p)表示斐波那契数列模p意义下的循环节
    有一个定理:L(pm)=L(p) × pm-1 
     
    未完待补,二次剩余实在是看不下去了。。。
     
  • 相关阅读:
    SPSS时间序列:频谱分析
    PureBasic—数控编辑框与调节块和进度条
    DELPHI2007 安装ACTIVEX插件的方法
    C++ builder的文件操作
    C++动态数组
    excel快速复制大量公式的方法
    Delphi XE5 如何与其他版本共存
    PureBasic 集成Form设计器的使用
    VS C++ 从一个窗口创建另一个窗口
    ENVI 5.0 Beta 体验——影像数据的显示
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/12078692.html
Copyright © 2020-2023  润新知