1. 程式人生 > >A Simple Math Problem(矩陣快速冪(模板))

A Simple Math Problem(矩陣快速冪(模板))

【題目來源】https://vjudge.net/problem/HDU-1757
【題意】
求解數k對應的f(k)%m,關係式如題面所示。
【思路】
既然給出了遞推式,又因為k的取值上限相當大,所以使用矩陣快速冪來實現f(k)的求解。這個時候就可以用到係數矩陣來表示題面給出的關係式。
什麼是係數矩陣呢?舉個例子(從麻省理工學院線性代數視訊上看的):
假如有三個未知數:x,y,z;
存在如下關係:(先不管是否有解)
2x+3y=z
x-y=2z
那麼用矩陣表示這個關係的話,如下:
這裡寫圖片描述
然而呢,這就是一個係數矩陣表示方程組。。
假設定為1,2,3矩陣。
所以呢,對於這道題,我們可以根據第二個關係式來推導係數矩陣,也就是1矩陣,然後把它用快速冪的思想求出係數矩陣的k-9次方,最後呢,再乘以2矩陣,得到3矩陣。
f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10)
再上面這個式子裡可以得到:
f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10)
f(x-1)=1*f(x-1)
f(x-2)=1*f(x-2)
f(x-3)=1*f(x-3)
f(x-4)=1*f(x-4)
f(x-5)=1*f(x-5)
f(x-6)=1*f(x-6)
f(x-7)=1*f(x-7)
f(x-8)=1*f(x-8)
f(x-9)=1*f(x-9)
由此得到係數矩陣(也就是1矩陣):
a0 a1 a2 a3 a4 a5 a6 a7 a8 a9
1_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 1_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_
0_ 0_ 0_ 0_ 0_ 0_ 0_ 0_ 1_ 0_
相對應的2矩陣為:
f(x-1) 0 0 0 0 0 0 0 0 0
f(x-2) 0 0 0 0 0 0 0 0 0
f(x-3) 0 0 0 0 0 0 0 0 0
f(x-4) 0 0 0 0 0 0 0 0 0
f(x-5) 0 0 0 0 0 0 0 0 0
f(x-6) 0 0 0 0 0 0 0 0 0
f(x-7) 0 0 0 0 0 0 0 0 0
f(x-8) 0 0 0 0 0 0 0 0 0
f(x-9) 0 0 0 0 0 0 0 0 0
f(x-10)0 0 0 0 0 0 0 0 0
附:
任何矩陣乘以單位矩陣都等於他本身。下面是5*5的單位矩陣:
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1。
然後,。。。。就沒然後了。。。
還有千萬要記得。。。定義矩陣*運算時,定義一個矩陣之後,要先清零。。。
【程式碼】

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<limits.h>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace
std; const int mod=1000000007; typedef unsigned long long ll; typedef long long LL; int k,m; struct mat { int a[11][11]; }ans,temp,base; mat operator*(mat s,mat t) { mat r; mem(r.a,0); for(int i=1; i<=10; i++) { for(int j=1; j<=10; j++) { for(int k=1; k<=10
; k++) { r.a[i][j]=r.a[i][j]+s.a[i][k]*t.a[k][j]; if(r.a[i][j]>=m) r.a[i][j]%=m; } } } return r; } void print(mat b) { for(int i=1;i<=10;i++) { for(int j=1;j<=10;j++) printf("%4d ",b.a[i][j]); printf("\n"); } } void init() { mem(ans.a,0); for(int i=1;i<=10;i++) ans.a[i][i]=1; for(int i=2;i<=10;i++) temp.a[i][i-1]=1; mem(base.a,0); for(int i=1;i<=10;i++) base.a[i][1]=10-i; } int pow_mat() { init(); while(k) { if(k&1) ans=ans*temp; temp=temp*temp; k>>=1; } ans=ans*base; return ans.a[1][1]; } int main() { while(~scanf("%d%d",&k,&m)) { mem(temp.a,0); for(int i=1; i<=10; i++) scanf("%d",&temp.a[1][i]); if(k<10) printf("%d\n",k%m); else { k-=9; printf("%d\n",pow_mat()); } } }