日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

蓝桥杯 算法提高 递推求值(矩阵快速幂)详解

發布時間:2025/3/20 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 蓝桥杯 算法提高 递推求值(矩阵快速幂)详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

問題描述

已知遞推公式:

F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5,

F(n, 2)=F(n-1, 1) + 3F(n-3, 1) + 2F(n-3, 2) + 3.

初始值為:F(1, 1)=2, F(1, 2)=3, F(2, 1)=1, F(2, 2)=4, F(3, 1)=6, F(3, 2)=5。

輸入n,輸出F(n, 1)和F(n, 2),由于答案可能很大,你只需要輸出答案除以99999999的余數。

輸入格式

輸入第一行包含一個整數n。

輸出格式

輸出兩行,第一行為F(n, 1)除以99999999的余數,第二行為F(n, 2)除以99999999的余數。

樣例輸入

4

樣例輸出

14
21

數據規模和約定

1<=n<=10^18。

分析

  • 這道題數據規模大,如果用暴力法解鐵定會超時。這時,我們不妨考慮用矩陣快速冪來解決這道題。
  • 矩陣快速冪是就求解遞推式的一種比較高效的手段,需要我們找到遞推式對應的矩陣運算等式,把求遞推式問題轉換為求矩陣乘冪問題,再利用快速冪求解矩陣的冪乘,最后計算結果即可。
  • 用Fibonacci數列來舉例,我們找到遞推式對應的等式
    (F(n)F(n?1))=(1110)?(F(n?1)F(n?2))\begin{pmatrix} F(n) \\ F(n-1) \end{pmatrix}=\begin{pmatrix} 1 &amp; 1 \\ 1 &amp; 0 \\ \end{pmatrix}*\begin{pmatrix} F(n-1) \\ F(n-2) \end{pmatrix} (F(n)F(n?1)?)=(11?10?)?(F(n?1)F(n?2)?)
    ,再把右邊的
    (F(n?1)F(n?2))\begin{pmatrix} F(n-1) \\ F(n-2) \end{pmatrix} (F(n?1)F(n?2)?)
    繼續往下分解到n-1=2,可得
    (F(n)F(n?1))=(1110)n?2?(F(2)F(1))\begin{pmatrix} F(n) \\ F(n-1) \end{pmatrix}=\begin{pmatrix} 1 &amp; 1 \\ 1 &amp; 0 \\ \end{pmatrix}^{n-2}*\begin{pmatrix} F(2) \\ F(1) \end{pmatrix} (F(n)F(n?1)?)=(11?10?)n?2?(F(2)F(1)?)
    ,這就把問題轉化為利用矩陣快速冪求
    (1110)n?2\begin{pmatrix} 1 &amp; 1 \\ 1 &amp; 0 \\ \end{pmatrix}^{n-2}(11?10?)n?2

注意:(F(n)F(n?1))\begin{pmatrix} F(n) \\ F(n-1) \end{pmatrix}(F(n)F(n?1)?) 中的每個元素都對應比 (F(n?1)F(n?2))\begin{pmatrix} F(n-1) \\ F(n-2) \end{pmatrix} (F(n?1)F(n?2)?)大一項,這是我們構造遞推式的方法

  • 放在這一道,這里題目給了6個已知項,再加上遞推式中有常數,我們可以基本斷定列矩陣中有7個元素,于是我們經猜想可得(找了一上午)等式左邊的列矩陣
    (F(n,1)F(n,2)F(n?1,1)F(n?1,2)F(n?2,1)F(n?2,2)1)\begin{pmatrix} F(n,1) \\ F(n,2) \\ F(n-1,1) \\ F(n-1,2) \\F(n-2,1) \\ F(n-2,2) \\ 1 \end{pmatrix} ???????????F(n,1)F(n,2)F(n?1,1)F(n?1,2)F(n?2,1)F(n?2,2)1????????????
    ,按照先前說的規律可得右邊的行矩陣
    (F(n?1,1)F(n?1,2)F(n?2,1)F(n?2,2)F(n?3,1)F(n?3,2)1)\begin{pmatrix} F(n-1,1) \\ F(n-1,2) \\F(n-2,1) \\ F(n-2,2) \\ F(n-3,1) \\ F(n-3,2) \\1 \end{pmatrix} ???????????F(n?1,1)F(n?1,2)F(n?2,1)F(n?2,2)F(n?3,1)F(n?3,2)1????????????
    ,最后按照遞推式寫出中間的方陣
    (0100205100032310000000100000001000000010000000001)\begin{pmatrix} 0&amp;1&amp;0&amp;0&amp;2&amp;0&amp;5 \\ 1&amp;0&amp;0&amp;0&amp;3&amp;2&amp;3 \\ 1&amp;0&amp;0&amp;0&amp;0&amp;0&amp;0 \\ 0&amp;1&amp;0&amp;0&amp;0&amp;0&amp;0 \\ 0&amp;0&amp;1&amp;0&amp;0&amp;0&amp;0 \\ 0&amp;0&amp;0&amp;1&amp;0&amp;0&amp;0 \\ 0&amp;0&amp;0&amp;0&amp;0&amp;0&amp;1 \end{pmatrix} ???????????0110000?1001000?0000100?0000010?2300000?0200000?5300001????????????
    ,而最后要求的冪等于1+(n?1?3)=n?31+(n-1-3)=n-31+(n?1?3)=n?3。至此,我們已經轉換成利用快速冪求矩陣乘冪問題了。
  • C++選手的話可以在定義Matrix結構體的時候重載"*"運算符以表示矩陣乘法,java選手則選擇可以在定義matrix類的時候寫一個表示矩陣乘法的multi()方法,這樣符合面向對象思想且有利于增加代碼的可讀性。剩下的矩陣快速冪代碼和普通快速冪代碼基本相同,不必累述。(見:快速冪(良心教程))

代碼如下

import java.util.*; public class Main {static final int mod=99999999;static long num[]=new long[] {6,5,1,4,2,3,1};static long n,ans1,ans2;static class Matrix{long mat[][]=new long[7][7];Matrix multi(Matrix a) { //矩陣乘法Matrix rec=new Matrix();for(int i=0;i<7;i++) {for(int k=0;k<7;k++) {if(this.mat[i][k]!=0)for(int j=0;j<7;j++) {rec.mat[i][j]=(rec.mat[i][j]+(this.mat[i][k]*a.mat[k][j])%mod)%mod;}}}return rec;}}//ST表示該方陣,E表示單位矩陣(其地位相當于整數1)static Matrix ST=new Matrix(),E=new Matrix();static void init() { //初始化for(int i=0;i<7;i++)E.mat[i][i]=1;ST.mat[0][1]=1;ST.mat[0][4]=2;ST.mat[0][6]=5;ST.mat[1][0]=1;ST.mat[1][4]=3;ST.mat[1][5]=2;ST.mat[1][6]=3;ST.mat[2][0]=1;ST.mat[3][1]=1;ST.mat[4][2]=1;ST.mat[5][3]=1;ST.mat[6][6]=1;}static Matrix matrix_pow(long n) { //矩陣快速冪Matrix rec=E,base=ST;while(n!=0) {if(n%2==1) {rec=rec.multi(base);}base=base.multi(base);n=n>>1;}return rec;}public static void main(String[] args) {Scanner cin=new Scanner(System.in);n=cin.nextLong();if(n<4) {int index=(int)(3-n)*2;System.out.println(num[index]);System.out.println(num[index+1]);}else {init();ST=matrix_pow(n-3);for(int i=0;i<7;i++) {ans1=(ans1+(ST.mat[0][i]*num[i])%mod)%mod; //求F(n,1)ans2=(ans2+(ST.mat[1][i]*num[i])%mod)%mod; //求F(n,2)}System.out.println(ans1);System.out.println(ans2);}} }

矩陣快速冪模板

矩陣類的模板,mat[][]數組的類型和N的大小都要根據實際情況來定。是否要取模以及mod的大小也是根據題目,一般規模較大的題目都會要求取模。

static class Matrix{mat[][]=new long[N][N]; //類的數據成員Matrix multi(Matrix a) { //矩陣乘法Matrix rec=new Matrix();for(int i=0;i<N;i++) {for(int k=0;k<N;k++) {if(this.mat[i][k]!=0)for(int j=0;j<N;j++) {rec.mat[i][j]=(rec.mat[i][j]+(this.mat[i][k]*a.mat[k][j])%mod)%mod;}}}return rec;} }

矩陣快速冪模板,預先要寫好init()函數初始化表示單位矩陣的Matrix類對象E和要求冪乘的方陣ST

Matrix matrix_pow(long n){Matrix rec=E,base=ST;while(b!=0){if(b%2==1){rec=rec.multi(base);}base=base.multi(base);n=n>>1;}return rec; }

總結

以上是生活随笔為你收集整理的蓝桥杯 算法提高 递推求值(矩阵快速幂)详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。