算法 {矩阵DP(矩阵优化递推DP)}
矩陣DP
定义
有個若干個DP (比如有3個DP: DP0[ N], DP1[ N], DP2[ N]
), 每一個DP的遞推式 滿足線性組合, 即
D
P
0
/
1
/
2
[
i
]
=
k
1
∗
D
P
0
[
i
−
1
]
+
k
2
∗
D
P
1
[
i
−
1
]
+
k
3
∗
D
P
2
[
i
−
1
]
DP0/1/2[ i] = k1*DP0[ i-1] + k2*DP1[i-1] + k3*DP2[i-1]
DP0/1/2[i]=k1∗DP0[i−1]+k2∗DP1[i−1]+k3∗DP2[i−1];
for( int i = 1; i < N; ++i){
DP0[ i] = k0*DP0[ i-1] + k1*DP1[ i-1] + k2*DP2[ i-1];
DP1[ i] = k3*DP0[ i-1] + k4*DP1[ i-1] + k5*DP2[ i-1];
DP2[ i] = k6*DP0[ i-1] + k7*DP1[ i-1] + k8*DP2[ i-1];
}
這個時間是 O ( N ) O(N) O(N)的, 如果 N N N很大 比如 > 1 e 8 >1e8 >1e8 那麼可以把以上過程 轉換為 矩陣乘法;
DP[3] = { DP0[0], DP1[0], DP2[0]}; (初值)
A[3][3] = { {k0, k3, k6}, {k1, k4, k7}, {k2, k5, k8}};
可以發現 執行矩陣乘法`DP * A = DPP` 會得到DPP[0]=DP0[1] DPP[1]=DP1[1] DPP[2]=DP2[1];
換句話說 `* A`表示: 進行了一次DP的遞推 (即對應樸素算法的for循環);
因此 要得到樸素算法的DP?[ N-1] 即進行了`N-1`次的遞推, 即`DP * A*...*A`(一共有N-1個A);
根據*矩陣乘法*的傳遞律, 比如你要進行5個遞推 那麼他等價於`(DP*A)*(A*A*A*A)`
因此`DP * A^n` 可以用快速冪計算, 有以下两种做法:
1: 你可以先求出`AA: A^n`, 然後最後執行DP*AA;
2: DP也可以直接參與到快速冪裡, 即`DP*(A^1) * (A^2) * (A^4) * ...`;
错误
比如要快速幂求A^k
, 最初答案矩阵 设置成全1 这是错误的!
矩阵乘法中的单位1 即单位矩阵, 不是全1, 而是主对角线为1 其他为0;
性质
算法
代碼
//{ ___DP_MatrixMultiply (矩阵优化递推DP)
template< class _T_> std::vector< _T_> ___DP_MatrixMultiply( std::vector<_T_> _initDP, std::vector<std::vector<_T_> > _factor, long long _count){
//< 比如`initDP = [DP0, DP1], factor: [[a,b], [c,d]]`, 则表示DP递推式为`DP0 = a*DP0 + b*DP1, DP1 = c*DP0 + d*DP1`;
// . `_count`为递推次数, 即`initDP`进行`count`次递推后 结果为*返回值*;
ASSERT_( _count >= 0, _count);
ASSERT_( _initDP.size()==_factor.size() && _factor.size()==_factor[0].size());
int const N = _initDP.size();
{ // `factor`转换为其转置矩阵
for( int i = 0; i < N; ++i){
for( int j = i+1; j < N; ++j){
std::swap( _factor[i][j], _factor[j][i]);
}
}
}
auto temp1 = _initDP;
auto temp2 = _factor;
while( _count > 0){
if( _count & 1){ // DP *= factor;
for( int col = 0; col < N; ++col){
temp1[ col] = 0;
for( int i = 0; i < N; ++i){
temp1[ col] += (_initDP[ i] * _factor[ i][ col]);
}
}
_initDP = temp1;
}
_count >>= 1;
{ // factor *= factor
for( int row = 0; row < N; ++row){
for( int col = 0; col < N; ++col){
temp2[ row][ col] = 0;
for( int i = 0; i < N; ++i){
temp2[ row][ col] += (_factor[ row][ i] * _factor[ i][ col]);
}
}
}
_factor = temp2;
}
}
return _initDP;
}
//} ___DP_MatrixMultiply
例题
@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=139273191
;
求4.....4
(长度为1e9)这个10进制数的取模值;
DP矩阵里 放一个常数;
@DELI;
@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=132818193
;`;
@DELI;
筆記
The nature of Matrix-Multiplication in Algorithm is
D
P
DP
DP, so it is vital to review some notion of
D
P
DP
DP:
0
T
i
m
e
(
O
r
d
e
r
)
Time(Order)
Time(Order), the DP-Value of Time-
i
i
i (
D
P
[
i
]
DP[i]
DP[i]) always depends on
D
P
[
<
i
]
DP[<i]
DP[<i];
.
.
For example,
F
i
b
o
n
a
c
c
i
[
i
]
=
F
i
b
o
n
a
c
c
i
[
i
−
1
]
+
F
i
b
o
n
a
c
c
i
[
i
−
2
]
Fibonacci[i] = Fibonacci[i-1] + Fibonacci[i-2]
Fibonacci[i]=Fibonacci[i−1]+Fibonacci[i−2];
1
State, at every Time-
i
i
i,
D
P
DP
DP has several
S
t
a
t
e
s
States
States;
.
.
e.g.,
D
P
[
n
]
DP[n]
DP[n] has just one-state (
D
P
[
i
]
DP[i]
DP[i]);
D
P
[
n
]
[
m
]
DP[n][m]
DP[n][m] has
m
m
m-states
D
P
[
i
]
[
0
,
1
,
.
.
.
,
m
−
1
]
DP[i][0,1,...,m-1]
DP[i][0,1,...,m−1];
@Delimiter
The Matrix-Multiplication in Algorithm must be in the form:
D
p
[
a
0
,
a
1
,
.
.
.
,
a
n
−
1
]
∗
F
a
c
t
o
r
[
k
0
,
0
k
0
,
1
.
.
.
k
0
,
n
−
1
.
.
.
k
n
−
1
,
0
k
n
−
1
,
1
.
.
.
k
n
−
1
,
n
−
1
]
=
R
e
s
u
l
t
[
b
0
,
b
1
,
.
.
.
,
b
n
−
1
]
Dp[a_0, a_1,..., a_{n-1}] * Factor\begin{bmatrix} k_{0,0}& k_{0,1} & ... & k_{0,n-1} \\ ... \\ k_{n-1,0} & k_{n-1,1} & ... & k_{n-1,n-1} \end{bmatrix} = Result[b_0, b_1,..., b_{n-1}]
Dp[a0,a1,...,an−1]∗Factor
k0,0...kn−1,0k0,1kn−1,1......k0,n−1kn−1,n−1
=Result[b0,b1,...,bn−1]
D
p
Dp
Dp must be a
1
∗
n
1 * n
1∗n Row-Matrix;
F
a
c
t
o
r
Factor
Factor must be a
n
∗
n
n*n
n∗n Square-Matrix;
Then,
R
e
s
u
l
t
Result
Result is a
1
∗
n
1 * n
1∗n Row-Matrix;
We called
D
p
,
R
e
s
u
l
t
Dp, Result
Dp,Result the
DP-Matrix
\text{ DP-Matrix}
DP-Matrix
If we denote
D
p
[
a
0
,
a
1
,
.
.
.
,
a
n
−
1
]
Dp[a_0, a_1,..., a_{n-1}]
Dp[a0,a1,...,an−1] as the DP-Time-
i
i
i (i.e.,
D
P
[
i
]
DP[i]
DP[i]), then
R
e
s
u
l
t
[
b
0
,
b
1
,
.
.
.
,
b
n
−
1
]
Result[b_0, b_1,..., b_{n-1}]
Result[b0,b1,...,bn−1] would be the DP-Time-
i
+
1
i+1
i+1 (i.e.,
D
P
[
i
+
1
]
DP[i+1]
DP[i+1]);
.
More specifically, the phrase
D
p
[
a
0
,
a
1
,
.
.
.
,
a
n
−
1
]
=
D
P
[
i
]
Dp[a_0, a_1,..., a_{n-1}] = DP[i]
Dp[a0,a1,...,an−1]=DP[i] means that,
D
P
[
i
]
DP[i]
DP[i] has
n
n
n
S
t
a
t
e
s
States
States
a
0
,
.
.
.
,
a
n
−
1
a_0, ..., a_{n-1}
a0,...,an−1;
.
So,
a
i
,
b
i
a_i, b_i
ai,bi denote the same DP-State, just the Time of
a
i
a_i
ai is
k
k
k and the Time of
b
i
b_i
bi is
k
+
1
k+1
k+1;
Then,
b
i
=
C
0
∗
a
0
+
C
1
∗
a
1
+
.
.
.
+
C
n
−
1
∗
a
n
−
1
b_i = C_0 * a_0 + C_1 * a_1 + ... + C_{n-1} * a_{n-1}
bi=C0∗a0+C1∗a1+...+Cn−1∗an−1 where
C
i
C_i
Ci are all
C
o
n
s
t
a
n
t
s
Constants
Constants;
.
That is,
b
i
bi
bi is a Linear-Combination of all
a
i
a_i
ai;
.
Cuz
C
i
C_i
Ci must be
C
o
n
s
t
a
n
t
s
Constants
Constants, the DP-State-Transformation must be in the form of Linear-Combination (i.e.,
Constant * DP-State
\text{Constant * DP-State}
Constant * DP-State) (if not, that DP not fit the Matrix-Multiplication);
.
.
e.g.,
D
P
[
i
]
=
D
P
[
i
−
1
]
∗
D
P
[
i
−
2
]
DP[i] = DP[i-1] * DP[i-2]
DP[i]=DP[i−1]∗DP[i−2] is Infeasible;
The utmost point is to clarify the correspondence between The-Time of the matrix-
D
p
[
.
.
.
]
Dp[...]
Dp[...] and The-Time of the DP of all its elements
a
i
a_i
ai;
.
e.g., Calculate the
S
[
i
]
=
∑
j
=
1
i
F
[
j
]
S[i] = \sum_{j = 1}^{i} F[j]
S[i]=∑j=1iF[j] where
F
[
]
F[]
F[] is the Fibonacci;
.
.
Suppose the DP-Time of the matrix
D
p
[
.
.
.
]
Dp[...]
Dp[...] is
i
i
i, and we let
a
0
=
F
[
i
]
,
a
1
=
F
[
i
+
1
]
,
a
2
=
S
[
i
]
a_0 = F[i], a_1 = F[i+1], a_2 = S[i]
a0=F[i],a1=F[i+1],a2=S[i] (suppose these three values are already gained);
.
.
We need to update
b
i
b_i
bi correctly, that is, to determine those
k
i
,
j
k_{i,j}
ki,j in the matrix-
F
a
c
t
o
r
Factor
Factor;
.
.
Then, the matrix-
R
e
s
u
l
t
Result
Result would be The-Time
i
+
1
i + 1
i+1 (cuz the matrix-
D
p
Dp
Dp is Time-
i
i
i); Therefore,
b
0
b_0
b0 denotes
F
[
i
+
1
]
F[i + 1]
F[i+1],
b
1
=
F
[
i
+
2
]
b_1 = F[i + 2]
b1=F[i+2],
b
2
=
S
[
i
+
1
]
b_2 = S[i + 1]
b2=S[i+1];
.
.
We need to find the relation between
a
i
,
b
j
a_i, b_j
ai,bj, so
b
0
=
a
1
b_0 = a_1
b0=a1,
b
1
=
a
0
+
a
1
b_1 = a_0 + a_1
b1=a0+a1,
b
2
=
a
2
+
a
1
b_2 = a_2 + a_1
b2=a2+a1; This is valid due to the form of every formula is Linear-Combination;
@Delimiter
Initially, if we set the matrix-
D
p
[
.
.
.
]
Dp[...]
Dp[...] as DP-Time-
0
0
0, we wanna it to be DP-Time-
i
i
i;
.
That is,
D
p
[
.
.
.
]
∗
F
a
c
t
o
r
∗
F
a
c
t
o
r
∗
.
.
.
∗
F
a
c
t
o
r
Dp[...] * Factor * Factor * ... * Factor
Dp[...]∗Factor∗Factor∗...∗Factor where the number of
F
a
c
t
o
r
Factor
Factor is
i
i
i; the result would be the DP-Time-
i
i
i;
.
Matrix-Multiplication satisfies the Combination-Property, then it can be transformed to
D
p
[
.
.
.
]
∗
(
F
a
c
t
o
r
i
)
Dp[...] * (Factor ^ i)
Dp[...]∗(Factori), we can use Binary-Exponentiation to solve it;
@DELI;
Property-0 \text{Property-0} Property-0
The elements
a
i
a_i
ai in the matrix-
D
p
[
a
0
,
a
1
,
.
.
.
]
Dp[a_0, a_1, ...]
Dp[a0,a1,...] can be divided into two-types:
0
a
i
a_i
ai is a DP-State; The value of
a
i
a_i
ai depends on the DP-Time of the matrix-
D
p
[
.
.
.
]
Dp[...]
Dp[...] (of course,
a
i
a_i
ai is not a Constant);
1
a
i
a_i
ai is a Constant; Whatever the DP-Time of the matrix-
D
p
[
.
.
.
]
Dp[...]
Dp[...] is,
a
i
a_i
ai is always the same;
For example,
d
p
[
i
]
=
2
∗
d
p
[
i
−
1
]
+
5
dp[i] = 2 * dp[i - 1] + 5
dp[i]=2∗dp[i−1]+5, then we transform it to
2
∗
d
p
[
i
−
1
]
+
1
∗
5
2 * dp[i - 1] + 1 * 5
2∗dp[i−1]+1∗5 which satisfying the requirement that
2
,
1
2,1
2,1 are Constants;
.
Let the matrix-
D
p
[
a
,
b
]
Dp[a,b]
Dp[a,b] be the DP-Time-
i
i
i where
a
=
d
p
[
i
]
,
b
=
5
a = dp[i], b = 5
a=dp[i],b=5;
.
Then the matrix-
R
e
s
u
l
t
[
c
,
d
]
Result[c,d]
Result[c,d] be the DP-Time-
i
+
1
i+1
i+1 where
c
=
d
p
[
i
+
1
]
=
2
∗
d
p
[
i
]
+
5
,
d
=
5
c = dp[i+1] = 2 * dp[i] + 5, d = 5
c=dp[i+1]=2∗dp[i]+5,d=5, so
c
=
2
∗
a
+
1
∗
b
,
d
=
b
c = 2 * a + 1 * b, d = b
c=2∗a+1∗b,d=b satisfying the Linear-Combination;
@Delimiter
Property-1 \text{Property-1} Property-1
Once the DP-Time of the matrix-
D
p
[
.
.
.
]
Dp[...]
Dp[...] is settled (suppose it is
i
i
i), then the DP-Time of all its DP-Elements
a
i
a_i
ai is also fixed;
.
e.g., Let the DP-Time of the matrix-
D
p
[
a
,
b
,
c
,
d
]
Dp[ a, b, c, d]
Dp[a,b,c,d] is
i
i
i, where
a
=
d
p
1
[
i
]
,
b
=
d
p
2
[
i
−
1
]
,
c
=
d
p
3
[
i
+
1
]
a = dp_1[i], b = dp_2[i-1], c = dp_3[i+1]
a=dp1[i],b=dp2[i−1],c=dp3[i+1] and
d
d
d is a Constant-Element;
.
.
Now, given you another matrix-
T
[
d
,
e
,
f
]
T[d, e, f]
T[d,e,f] whose DP-Time is
j
j
j, then we would know that,
d
=
d
p
1
[
j
]
,
e
=
d
p
2
[
j
−
1
]
,
f
=
d
p
3
[
j
+
1
]
d = dp_1[j], e = dp_2[j - 1], f = dp_3[j + 1]
d=dp1[j],e=dp2[j−1],f=dp3[j+1]$;