【學習筆記】快速冪+矩陣+矩陣乘法+矩陣快速冪
阿新 • • 發佈:2018-12-24
今天晚上我學習了矩陣
1、快速冪
通常,我們要算是這麼算的:
ans := 1;
for i := 1 to p do
ans := ans * b mod k;
顯然,時間複雜度是O(p)
但是萬一p很大,比如呢,暴力顯然是Tle了
那麼快速冪可以將O(p)優化成O(logp)級別
同樣是算,快速冪的核心部分:
function pow(b,p,k:int64):int64;
begin
if p = 0 then exit(1 mod k);
pow := pow(b,p >> 1 ,k);
pow := pow * pow mod k;
if p mod 2 = 1 then pow := pow * b mod k;
end;
var
b,p,k:int64;
function pow(b,p,k:int64):int64;
begin
if p = 0 then exit(1 mod k);
pow := pow(b,p >> 1,k);
pow := pow * pow mod k;
if p mod 2 = 1 then pow := pow * b mod k;
end;
begin
readln(b,p,k);
writeln(b,'^',p,' mod ',k,'=',pow(b,p,k));
end.
2、矩陣
關於矩陣,這裡講的很好
矩陣,就是像這樣的:
8 2 3 6
1 8 3 6
2 8 3 7
顯然,這是一個3*4的矩陣
那麼矩陣的運算呢?
- 矩陣加法
矩陣的加法就是對應位置加起來,即 - 矩陣減法
矩陣的減法與加法類似,即 - 矩陣乘一個數
簡單的,就是矩陣中每一個數乘當前數 - 矩陣乘法
矩陣的乘法比較複雜,而且必須是m*p的矩陣與p*n的矩陣相乘得到一個m*n的矩陣
公式是
3、矩陣快速冪
顧名思義,就是矩陣的快速冪。。
放一道模板題有助消化
針對這道題來講
暴力矩陣乘法會Tle
探究一下矩陣的運算滿足的法則
- 乘法交換律,顯然不行,因為矩陣的乘法是有要求的
- 乘法結合律,滿足,即
滿足結合律,說明什麼?
可以用快速冪!!!
那麼,矩陣的快速冪我們給他一個名字:矩陣快速冪
如何實現?
套快速冪的模板!只要把普通乘法部分改成矩陣乘法就好了
不過有一個問題:矩陣的0次冪是什麼?
因為任何數的0次冪是1,我們也發現了一個特殊的矩陣:左上右下對角線為1,其他都為0的矩陣
任何數乘1都為本身,任何矩陣乘這個矩陣也不變,那麼我們初始化成這個矩陣就好了
Code:
const mo = 1000000007;
type
ar = array[0..100,0..100] of int64;
var
a,b,c:ar;
n,m:int64;
i,j:longint;
procedure mul(a,b:ar);
var
i,j,k:longint;
begin
fillchar(c,sizeof(c),0);
for i := 1 to n do
for j := 1 to n do
for k := 1 to n do
c[i][j] := (c[i][j] + a[i][k] * b[k][j]) mod mo;
end;
procedure update(var a:ar;b:ar);
var
i,j:longint;
begin
for i := 1 to n do
for j := 1 to n do
a[i][j] := b[i][j];
end;
procedure pow(p:int64);
var
i,j,k:longint;
begin
if p = 0 then
begin
for i := 1 to n do a[i][i] := 1;
exit;
end;
pow(p >> 1);
mul(a,a);
update(a,c);
if p mod 2 = 1 then
begin
mul(a,b);
update(a,c);
end;
end;
begin
readln(n,m);
for i := 1 to n do
begin
for j := 1 to n do
read(b[i][j]);
readln;
end;
pow(m);
for i := 1 to n do
begin
for j := 1 to n do write(a[i][j],' ');
writeln;
end;
end.
用Fibonacci數列練練手:LuoGu1962
首先,我們需要推匯出一個矩陣,使得通過乘這個矩陣,我們手中的數列可以發展下去
由斐波那契公式可知第i項只與前兩項有關
那麼可以構造一個列向量B:
因為:
所以我們可以建立矩陣:
那就先求後面那個矩陣的次冪,再乘列向量B得到答案
Code:
const mo = 1000000007;
type
ar = array[0..10,0..10] of int64;
var
a,b,c:ar;
d,e:array[0..100] of int64;
i,j:longint;
n:int64;
procedure mul(a,b:ar);
var
i,j,k:longint;
begin
fillchar(c,sizeof(c),0);
for i := 1 to 2 do
for j := 1 to 2 do
for k := 1 to 2 do
c[i][j] := (c[i][j] + a[i][k] * b[k][j]) mod mo;
end;
procedure update(var a:ar;b:ar);
var
i,j:longint;
begin
for i := 1 to 2 do
for j := 1 to 2 do
a[i][j] := b[i][j];
end;
procedure pow(p:int64);
var
i:longint;
begin
if p = 0 then
begin
for i := 1 to 2 do a[i][i] := 1;
exit;
end;
pow(p >> 1);
mul(a,a);
update(a,c);
if p mod 2 = 1 then
begin
mul(a,b);
update(a,c);
end;
end;
begin
readln(n);
if n <= 2 then
begin
writeln(1);
halt;
end;
dec(n,2);
b[1][1] := 1;
b[1][2] := 1;
b[2][1] := 1;
pow(n);
fillchar(c,sizeof(c),0);
d[1] := 1; d[2] := 1;
for i := 1 to 2 do
for j := 1 to 2 do
e[i] := (e[i] + a[i][j] * d[j]) mod mo;
writeln(e[1]);
end.
再來一個模板:LuoGu1939
題目給出:
我們按照剛才斐波那契的套路構造矩陣
首先,構造列向量
因為: