概述
Description
. 动态规划的实现形式之一是递推,因此递推在oi中十分重要。在某信息学的分支学科中,LC学会了如何求一阶线性递推数列。由于他现在正在学习主干学科,因此希望知道求出N阶线性递推数列。为此,他了解到以下内容:
一个N阶线性递推式是这样的式子:
F
i
=
a
0
∗
F
i
−
n
+
a
1
∗
F
+
i
−
(
n
−
1
)
+
.
.
.
+
a
n
−
1
∗
F
i
−
1
+
a
n
F_i=a_0*F_{i-n}+a_1*F+{i-(n-1)}+...+a_{n-1}*F_{i-1}+a_n
Fi=a0∗Fi−n+a1∗F+i−(n−1)+...+an−1∗Fi−1+an
也就是说,这个数列的每一项都是由他之前的连续N项加权相加所得。其中还包括一个常数an。
例如,当N=2,a0=a1=1,a2=0时,这个式子就是我们熟悉的斐波那契数列。当然,作为边界条件。f0,f1,…fn-1都是已知的。
Lc对如何去求这个式子一筹莫展,因此他想请你帮忙。你的任务是对于一个给定的N阶线性递推式,求出他的第k项。
Input
第一行两个整数:n,k。其中n表示这是一个N阶线性递推式,k表示你需要球的那一项。
第二行有n+1个整数:a0,a1,…an,表示这个递推式的系数。
第三行有n个整数:f0,f1,…,fn-1表示数列的初始值。
Output
只有一行,其中只有一个整数,表示这个数列第k项的值。由于数据较大,你只需输出mod 9973的值。
Sample Input
2 10
1 1 0
0 1
Sample Output
55
解题思路
那我真的很失语啊,运行内存爆了一直RE,我以为是我数组开小了: )
首先构造初始矩阵
(为了方便理解所以从
1
1
1开始存,一共
n
n
n个数那么数组大小应该是
1
∗
(
n
+
1
)
1 * (n + 1)
1∗(n+1))
A
=
[
f
[
1
]
f
[
2
]
.
.
.
f
[
n
]
1
]
A = begin{bmatrix} f[1] & f[2] &... &f[n] &1 end{bmatrix}
A=[f[1]f[2]...f[n]1]
然后构造一个转移矩阵
大小设为
(
n
+
1
)
∗
(
n
+
1
)
(n + 1) * (n + 1)
(n+1)∗(n+1)
-
F i = a 0 ∗ F i − n + a 1 ∗ F + i − ( n − 1 ) + . . . + a n − 1 ∗ F i − 1 + a n F_i=a_0*F_{i-n}+a_1*F+{i-(n-1)}+...+a_{n-1}*F_{i-1}+a_n Fi=a0∗Fi−n+a1∗F+i−(n−1)+...+an−1∗Fi−1+an
算 f [ n + 1 ] f[n + 1] f[n+1]时所用的数是 f [ 1 ] f [ 2 ] . . . f [ n ] f[1] f[2]...f[n] f[1]f[2]...f[n]
算 f [ n + 2 ] f[n + 2] f[n+2]时所用的数是 f [ 2 ] f [ 3 ] . . . f [ n + 1 ] f[2] f[3]...f[n + 1] f[2]f[3]...f[n+1]
所有数向前推一位,第一个数直接推掉不用
B = [ 0 0 0 1 0 0 0 1 0 0 0 . . . 0 0 . . . ] B =begin{bmatrix} 0 & 0 & 0 & & \ 1 & 0 & 0 & & \ 0 & 1 & 0 & & \ 0 & 0 & ... & & \ 0 & 0 & ...& & end{bmatrix} B=⎣⎢⎢⎢⎢⎡0100000100000......⎦⎥⎥⎥⎥⎤ -
最后一个数更新为 f n f_n fn
B = [ 0 0 0 a 1 1 0 0 a 2 0 1 0 a 3 0 0 . . . . . . 0 0 . . . a n ] B =begin{bmatrix} 0 & 0 & 0 & a_1 & \ 1 & 0 & 0 & a_2 & \ 0 & 1 & 0 & a_3 & \ 0 & 0 & ... & ... & \ 0 & 0 & ...& a_n & end{bmatrix} B=⎣⎢⎢⎢⎢⎡0100000100000......a1a2a3...an⎦⎥⎥⎥⎥⎤
这个时候 A A A矩阵中最后一个 1 1 1的作用就体现出来了,因为要乘上一个 a n a_n an -
最后一列用来传递最后的那个 1 1 1
B = [ 0 0 0 a 1 0 1 0 0 a 2 0 0 1 0 a 3 0 0 0 . . . . . . 0 0 0 . . . a n 1 ] B = begin{bmatrix} 0 & 0 & 0 & a_1 &0 \ 1 & 0 & 0 & a_2 & 0\ 0 & 1 & 0 & a_3 & 0\ 0 & 0 & ... & ... & 0\ 0 & 0 & ...& a_n &1 end{bmatrix} B=⎣⎢⎢⎢⎢⎡0100000100000......a1a2a3...an00001⎦⎥⎥⎥⎥⎤
问题转换成
a
n
s
=
A
∗
B
k
ans = A * B^k
ans=A∗Bk,然后输出
a
n
s
[
1
]
[
1
]
ans[1][1]
ans[1][1]
但是
A
A
A里面包含了
f
[
1
]
.
.
f
[
n
]
f[1]..f[n]
f[1]..f[n],所以
a
n
s
ans
ans其实算出了
f
[
n
+
1
]
.
.
f
[
n
+
k
]
f[n + 1]..f[n + k]
f[n+1]..f[n+k]
那么
a
n
s
=
A
∗
B
k
−
n
+
1
ans = A * B^{k - n + 1}
ans=A∗Bk−n+1,输出
a
n
s
[
1
]
[
n
]
ans[1][n]
ans[1][n]
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#define ll long long
using namespace std;
const int Mod = 9973;
struct DT{
int n, m;
ll aed[20][20];
}A, B, ans;
int n;
ll k;
DT operator *(DT a, DT b){//矩阵乘法
DT c;
memset (c.aed, 0, sizeof (c.aed));
c.n = a.n, c.m = b.m;
for (int k = 1; k <= a.m; k++)
for (int i = 1; i <= c.n; i++)
for (int j = 1; j <= c.m; j++)
c.aed[i][j] = (c.aed[i][j] + a.aed[i][k] * b.aed[k][j] % Mod) % Mod;
return c;
}
void power (ll x){
if (x == 1)
{
B = A;
return;
}
power (x / 2);
B = B * B;
if (x % 2) B = B * A;
}
int main(){
scanf ("%d%lld", &n, &k);
A.n = n + 1, A.m = n + 1;//此处的A不是思路中的A,A和B都是用来算幂的
for (int i = 1; i <= n + 1; i++)
{
scanf ("%lld", &A.aed[i][n]);//a数组放入转移矩阵
A.aed[i][n] %= Mod;
}
for (int i = 1; i < n; i++)
A.aed[i + 1][i] = 1;//转移f
A.aed[n + 1][n + 1] = 1;//转移最后一个1
power (k - n + 1);//快速幂
ans.n = 1, ans.m = n + 1;//这个ans是思路中的初始矩阵A和答案矩阵ans
for (int i = 1; i <= n; i++)
{
scanf ("%lld", &ans.aed[1][i]);
ans.aed[1][i] %= Mod;
}
ans.aed[1][n + 1] = 1;
ans = ans * B;
printf ("%lld", ans.aed[1][n]);
}
最后
以上就是无聊花生为你收集整理的【矩阵乘法】【快速幂】递推的全部内容,希望文章能够帮你解决【矩阵乘法】【快速幂】递推所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复