蓝桥杯 算法提高 递推求值(矩阵快速幂)详解
傳送門
問題描述
已知遞推公式:
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 & 1 \\ 1 & 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 & 1 \\ 1 & 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 & 1 \\ 1 & 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&1&0&0&2&0&5 \\ 1&0&0&0&3&2&3 \\ 1&0&0&0&0&0&0 \\ 0&1&0&0&0&0&0 \\ 0&0&1&0&0&0&0 \\ 0&0&0&1&0&0&0 \\ 0&0&0&0&0&0&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; }總結
以上是生活随笔為你收集整理的蓝桥杯 算法提高 递推求值(矩阵快速幂)详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数论基础之快速幂(详细教程)
- 下一篇: 枚举法用于逻辑问题的处理