Related blog: https://blog.csdn.net/china_xyc/article/details/89819376#commentBox
Matrix multiplication can be optimized on the subject DP, we have the following requirements:
- Only adder transfer type, clears, subtraction etc., max and min is not allowed in
- Where the transfer coefficient on the first few dp result must be a constant
- The number of transitions in general Super Multi
- Since the number of times of transfer, generally have a modulus within the range of int
In summary, an example:
dp[i]=a×dp[i−1]+b×dp[i−2]+c×dp[i−3]
Wherein, a, b, c are constants, and the required matrix optimization of the DP, often i 2 ^ 128 or the like, particularly Kichiku particularly large number;
because the optimized matrix multiplication find DP [i] is in O time log (i) is completed.
So, how to achieve matrix multiplication, its principle is Shane?
Matrix multiplication requires two matrices A and B, A is an n × p, B is the size of p × m, below
For ease of explanation, we give examples of Fibonacci deed.
Fibonacci transfer formula is: dp [i] = dp [ i-1] + dp [i-2].
We then (dp [i], dp [ i-1]) regarded as a 1 × 2 matrix A is
each time multiplied by the matrix A is equivalent to transfer F.:
|. 1. 1 |
| 0. 1 |
the results is: (dp [i] + dp [i-1], dp [i]), which is (dp [i + 1], dp [i])
then once every 8 times required matrix multiplication operations, while the original state transition required only once, so do not see matrix multiplication algorithm on a waste wood it. .
The key is! Matrix multiplication has associativity, hey hey hey, then we can begin to quickly power up! Look at it this way O (n) algorithm optimization has become a simple O (8 × logn) algorithm in n Fried Chicken Fried Chicken big metamorphosis time we can use this optimized.
Do your own examples https://www.luogu.org/problem/P5343
Knowledge used: a set of intersected (bitset <N> = and &) linear recursive (DP) matrix acceleration ( matrix flash power ) (in fact, somewhat like a scroll array)
linear recursive feeling is: f (n) = f (n-1) + f (n-2), and then to know the value f (1), f (2 ) , the introduction of f (3) value, and then has to recursive down, it is to know the value of the foregoing go We know the value of the latter.
#include <cstdio> #include <cstring> #include <iostream> #include <bitset> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 105; const int mod = 1e9+7; ll n; int m,x; bitset<maxn> a,b; ll g[maxn][maxn],tmp[maxn][maxn],res[maxn][maxn]; ll dp[maxn]; void mult(ll a[][maxn],ll b[][maxn]){ memset(tmp,0,sizeof(tmp)); for(int i=1; i<=100; i++){ for(int j=1; j<=100; j++){ for(int k=1; k<=100; k++){ tmp[i][j] = (tmp[i][j] + a[i][k]*b[k][j]%mod)%mod; } } } for(int i=1; i<=100; i++){ for(int j=1; j<=100; j++){ a[i][j] = tmp[i][j]; } } } void qpow(ll a[][maxn],ll N){ memset(res,0,sizeof(res)); for(int i=1; i<=100; i++){ res[i][i] = 1; } while(N){ if(N&1) mult(res,a); mult(a,a); N>>=1; } for(int i=1; i<=100; i++){ for(int j=1; j<=100; j++){ a[i][j] = res[i][j]; } } } int main(){ scanf("%lld%d",&n,&m); for(int i=0; i<m; i++){ scanf("%d",&x); a[x] = 1; } scanf("%d",&m); for(int i=0; i<m; i++){ scanf("%d",&x); b[x] = 1; } a &= b; for(int i=1; i<=100; i++){ if(a[i]) g[1][i]=1; } for(int i=2; i<=100; i++){ g[i][i-1] = 1; } // dp[0] = 1; // for(int i=0; i<=100; i++){ // for(int j=1; j<=i; j++){ // if(a[j]){ // dp[i] = (dp[i] + dp[i-j] )%mod; // } // } // } // if(n<=99) printf("%d\n", dp[n]); // else{ // qpow( g ,n-99); // ll ans = 0; // for(int i=1; i<=100; i++){ // = ANS (ANS + DP [I-100] * G [. 1] [I]% MOD) MOD%; // } // the printf ( "% LLD \ n-", ANS); // } // original direct matrix fast power can ah .. since f (1) = 0, then as the first to make a direct qpow (G, N- 0 ); the printf ( " % LLD \ n- " , G [ . 1 ] [ . 1 ]) ; }