矩陣乘法就是指一個a*b的矩陣和一個b*c的矩陣相乘得到一個a*c的矩陣
我們分別叫做A矩陣,B矩陣和C矩陣。
C[i][j]=
而用矩陣乘法優化dp時,實際上是一個矩陣自己與自己相乘,所以可以看做是矩陣的冪運算。
而關於冪運算,自然可以用快速冪來優化。
——————————————————————————————————————————–前話到此爲止
我們都知道dp的實質就是遞推
先舉個例子吧,比如用矩陣乘法優化快速求斐波那契數列。
我們都知道斐波那契數列的遞推式爲f[i]=f[i-2]+f[i-1]
我們可以將這個式子轉化成爲一個矩陣A
F[i] F[i-1]
F[i-1] F[i-2]
與另一個矩陣B
1 1
1 0
相乘
得出來矩陣C
F[i]+F[i-1] F[i]
F[i] F[i-1]
最後實際上就變成了
F[i+1] F[i]
F[i] F[i-1]
實際上是i++的原矩陣。
而當矩陣C繼續與B相乘的時候,顯然又會的出F[i+2]相關的矩陣
那麼實際上我們進行的操作就是由一個矩陣
F[3] F[2]
F[2] F[1]
與矩陣不斷的相乘。
那麼實際上就只需要求出B矩陣的冪再與A相乘。
關於實現上,我們知道正常的快速冪中res/ans(即記錄返回值的量)的初始值是1
那麼矩陣的快速冪中,記錄返回矩陣的初始矩陣是什麼樣的呢。
經過大量推理(julizi),我發現實際上這個矩陣是一個除了左上→右下對角線爲1,其餘都爲0的矩陣,大家也可以自己推一推(jujulizi),其實也很好理解,畢竟c[i][j]=a[i][k]
看到我以上口胡沒看懂的可以自己用代碼print一下矩陣什麼的..不過畢竟入門題沒啥難度
#include<bits/stdc++.h>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
const int maxn=4010;
const int INF=1e9+7;
const int mod=10000;
using namespace std;
/*----------------------------------------------------------------------------*/
inline ll read()
{
char ls;ll x=0,sng=1;
for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
return x*sng;
}
/*----------------------------------------------------------------------------*/
int fib[]={0,1};
struct kaga
{
ll v[2][2];
kaga friend operator *(kaga a,kaga b)
{
kaga c;
fer(i,0,1)
fer(j,0,1)
{
c.v[i][j]=0;
fer(k,0,1)
c.v[i][j]=(c.v[i][j]+a.v[i][k]*b.v[k][j])%mod;
}
return c;
}
}a,b,c;
void print(kaga a)
{
fer(i,0,1)
{
fer(j,0,1)
cout<<a.v[i][j]<<" ";
cout<<endl;
}
}
void init()
{
a.v[0][0]=2;a.v[0][1]=a.v[1][0]=a.v[1][1]=1;
b.v[0][0]=b.v[1][0]=b.v[0][1]=1;b.v[1][1]=0;
c.v[0][1]=c.v[1][0]=0;c.v[1][1]=c.v[0][0]=1;
//print(a);
//print(b);
//print(c);
}
int main()
{
int n;
while(scanf("%d",&n))
{
if(n==-1)return 0;
if(n<=1)
{
cout<<fib[n]<<endl;
continue;
}
n--;
init();
for(;n;n>>=1,b=b*b)
if(n&1)c=b*c;
a=a*c;
cout<<a.v[1][1]<<endl;
}
}
(這代碼是真的醜)