Talking about Matrix Acceleration Algorithm

Preface

(Look at this article, please first understand what a matrix is)

Matrix acceleration is a very magical algorithm, it can solve complex problems in a short time under extreme data, and it is also very simple. Let's start with examples:

Example 1: Fibonacci item n

The Fibonacci sequence satisfies f(1)=f(2)=1,f(i)=f(i-1)+f(i-2),i>2, ask f(n). (N<=1e9)

This data is large and cannot be solved routinely by recursion. Then let's not turn a detour, just start the formula derivation:

Because of f_{n}=f_{n-1}+f_{n-2}(key recurrence), it can be put f_{n-1}*1+f_{n-2}*1into a matrix multiplication (n*m and m*q matrix). Because it is 2 terms by 2 terms, so m=2, in order to achieve a regular cumulative multiplication, it is necessary to ensure that the result is also a matrix of n*2, so q=2. Because there are no other required numbers, n=1. The matrix is , after multiplying, the position of (1,1) is f_{n}. However f_{n+1}, the left matrix is required to be \begin{bmatrix} f_{n} &f_{n-1} \end{bmatrix}, so the position of (2,2) must be obtained by the "addition and multiplication" operation of f_{n-1}, f_{n-2}and the other two numbers f_{n-1}. Obviously,, f_{n-1}=f_{n-1}*1+f_{n-2}*0so the whole multiplication is \begin{bmatrix} f_{n-1} &f_{n-2} \end{bmatrix}*\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}, can be obtained \begin{bmatrix} f_{n} & f_{n-1} \end{bmatrix}, and then multiplied by one to \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}get \begin{bmatrix} f_{n+1} & f_{n} \end{bmatrix}, and so on. Therefore \begin{bmatrix} f_{2} &f_{1} \end{bmatrix}*\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^{n-2}=\begin{bmatrix} f_{n} & f_{n-1} \end{bmatrix}, f2 and f1 are known, and a matrix is ​​used to quickly exponentiate them.

(Code own water)

Example 2: The sequence of TR

TR likes mathematics very much, and often takes out draft paper to study strange mathematical problems. Recently, he suddenly became interested in the sequence of numbers. He found a sequence of numbers similar to Fibonacci, namely: Tn=1*f1+ 2*f2+3*f3+……+n*fn (fn is the value of the nth term of Fibonacci), now TR would like to ask you to help find the value of Tn%m (1≤n,m≤2^31- 1).

Suppose V_{n}=n*f_{n}, then

V_{n}=n*f_{n-1}+n*f_{n-2}

V_{n}=(n-1)*f_{n-1}+f_{n-1}+(n-2)*f_{n-2}+2*f_{n-2}

V_{n}=V_{n-2}+V_{n-1}+2*f_{n-2}+f_{n-1}

So T_{n}=T_{n-1}*1+V_{n-2}*1+V_{n-1}*1+f_{n-2}*2+f_{n-1}*1(key recursion), the left matrix is ​​set to \begin{bmatrix} T_{n-1} &V_{n-2} &V_{n-1} &f_{n-2} &f_{n-1} \end{bmatrix}, and then the

V_{n-1}=T_{n-1}*0+V_{n-2}*0+V_{n-1}*1+f_{n-2}*0+f_{n-1}*0

V_{n}=T_{n-1}*0+V_{n-2}*1+V_{n-1}*1+f_{n-2}*2+f_{n-1}*1

f_{n-1}=T_{n-1}*0+V_{n-2}*0+V_{n-1}*0+f_{n-2}*0+f_{n-1}*1

f_{n}=T_{n-1}*0+V_{n-2}*0+V_{n-1}*0+f_{n-2}*1+f_{n-1}*1

So \begin{bmatrix} T_{n-1} &V_{n-2} &V_{n-1} &f_{n-2} &f_{n-1} \end{bmatrix}*\begin{bmatrix} 1 &0 &0 &0 &0 \\ 1 &0 &1 &0 &0 \\ 1 &1 &1 &0 &0 \\ 2 &0 &2 &0 &1 \\ 1 &0 &1 &1 &1 \end{bmatrix}=\begin{bmatrix} T_{n} &V_{n-1} &V_{n} &f_{n-1} &f_{n} \end{bmatrix}.

do you understand? Finally \begin{bmatrix} T_{2} &V_{1} &V_{2} &f_{1} &f_{2} \end{bmatrix}* \begin{bmatrix} 1 &0 &0 &0 &0 \\ 1 &0 &1 &0 &0 \\ 1 &1 &1 &0 &0 \\ 2 &0 &2 &0 &1 \\ 1 &0 &1 &1 &1 \end{bmatrix}^{n-2} =\begin{bmatrix} T_{n} &V_{n-1} &V_{n} &f_{n-1} &f_{n} \end{bmatrix}, use matrix fast exponentiation.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,mod;
struct matrix{
    int n,m;
    long long c[105][105];
    matrix(){memset(c,0,sizeof(c));}
    matrix operator*(const matrix&a){
        matrix r;r.n=n,r.m=a.m;
        for(int i=1;i<=r.n;i++)
            for(int j=1;j<=r.m;j++)
                for(int k=1;k<=m;k++)r.c[i][j]=(r.c[i][j]+c[i][k]*a.c[k][j])%mod;
        return r;
    }
}a,b;
matrix mpow(matrix a,long long b){
    matrix res;res.n=res.m=a.n;
    for(int i=1;i<=res.n;i++)res.c[i][i]=1;
    for(;b;b>>=1){
        if(b&1)res=res*a;
        a=a*a;
    }
    return res;
}
int main()
{
    scanf("%lld%lld",&n,&mod);
    if(n==1){
        printf("%lld",1%mod);
        putchar('\n');
        return 0;
    }
    a.n=1,a.m=5;
    a.c[1][1]=3,a.c[1][2]=a.c[1][4]=a.c[1][5]=1,a.c[1][3]=2;
    b.n=b.m=5;
    b.c[1][1]=1;
    b.c[2][1]=b.c[2][3]=b.c[3][1]=b.c[3][2]=b.c[3][3]=1;
    b.c[4][1]=b.c[4][3]=2,b.c[4][5]=1;
    b.c[5][1]=b.c[5][3]=b.c[5][4]=b.c[5][5]=1;
    a=a*mpow(b,n-2);
    printf("%lld",a.c[1][1]%mod);
    putchar('\n');
    return 0;
}

Example 3: [Selected by Shandong Province] Recursive Sequence (Version 2)

to sum up

(For example questions one and two, just understand one solution) The matrix acceleration method is to first list the key recurrence formula (the right side must be a one-time m-term), and then list the 1*m and m*m matrices according to the formula, and then It's that simple.

(update2021.3.13) Extension: Generalized Moment Multiplication

The above method seems to only solve the recursive formula composed of plus and minus signs. In fact, the formula connected by taking the max and min symbols can also be optimized with a matrix. At this time, the generalized matrix multiplication is used:

C=A*B,C(i,j)=max/min(A(i,k)+B(k,j)), (This is just one of them)

It can be proved that the generalized matrix multiplication still satisfies the associative law, but does not satisfy the distribution rate, but this is enough, because the matrix acceleration only needs the associative law.

Because of getting rid of the constraints of plus and minus signs, matrix acceleration can optimize many seemingly unoptimized problems. Dynamic DP is an algorithm established on the basis of generalized moment multiplication.

Guess you like

Origin blog.csdn.net/weixin_43960287/article/details/88993370