Falando sobre Matrix Acceleration Algorithm

Prefácio

(Olhe para este artigo, primeiro entenda o que é uma matriz)

A aceleração de matriz é um algoritmo muito mágico, pode resolver problemas complexos em um curto espaço de tempo com dados extremos e também é muito simples. Vamos começar com exemplos:

Exemplo 1: item de Fibonacci n

A sequência de Fibonacci satisfaz f (1) = f (2) = 1, f (i) = f (i-1) + f (i-2), i> 2, pergunte f (n). (N <= 1e9)

Esses dados são grandes e não podem ser resolvidos rotineiramente por recursão. Então, não vamos fazer um desvio, basta começar a derivação da fórmula:

Por causa de f_ {n} = f_ {n-1} + f_ {n-2}(recorrência de chave), ele pode ser colocado f_ {n-1} * 1 + f_ {n-2} * 1em uma multiplicação de matriz (matriz n * me m * q). Por ser 2 termos por 2 termos, então m = 2, para obter uma multiplicação cumulativa regular, é necessário garantir que o resultado também seja uma matriz de n * 2, então q = 2. Como não há outros números obrigatórios, n = 1. A matriz é , depois de multiplicada, a posição de (1,1) é f_ {n}. No entanto f_ {n + 1}, a matriz da esquerda é necessária para ser \ begin {bmatrix} f_ {n} & f_ {n-1} \ end {bmatrix}, de modo que a posição da (2,2) deve ser obtido por a "adição e multiplicação" operação de f_ {n-1}, f_ {n-2}e os outros dois números f_ {n-1}. Obviamente, f_ {n-1} = f_ {n-1} * 1 + f_ {n-2} * 0então, toda a multiplicação é \ begin {bmatrix} f_ {n-1} & f_ {n-2} \ end {bmatrix} * \ begin {bmatrix} 1 e 1 \\ 1 & 0 \ end {bmatrix}, pode ser obtida \ begin {bmatrix} f_ {n} & f_ {n-1} \ end {bmatrix}e, em seguida, multiplicada por um para \ begin {bmatrix} 1 e 1 \\ 1 e 0 \ end {bmatrix}obter \ begin {bmatrix} f_ {n + 1} & f_ {n} \ end {bmatrix}, e assim por diante. Portanto \ 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 e f1 são conhecidos e uma matriz é usada para exponenciá-los rapidamente.

(Codifique a própria água)

Exemplo 2: A sequência de TR

TR gosta muito de matemática e costuma pegar rascunhos para estudar problemas matemáticos estranhos. Recentemente, ele de repente se interessou pela sequência de números. Ele encontrou uma sequência de números semelhante a Fibonacci, a saber: Tn = 1 * f1 + 2 * f2 + 3 * f3 + …… + n * fn (fn é o valor do enésimo termo de Fibonacci), agora TR gostaria de pedir sua ajuda para encontrar o valor de Tn% m (1≤n, m≤2 ^ 31 - 1).

Suponha V_ {n} = n * f_ {n}então

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}

Então T_ {n} = T_ {n-1} * 1 + V_ {n-2} * 1 + V_ {n-1} * 1 + f_ {n-2} * 2 + f_ {n-1} * 1(recursão chave), a matriz esquerda é definida como \ begin {bmatrix} T_ {n-1} & V_ {n-2} & V_ {n-1} & f_ {n-2} & f_ {n-1} \ end {bmatrix}, e então o

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

Então \ 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}.

você entende? Finalmente \ 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 a exponenciação rápida da matriz.

#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;
}

Exemplo 3: Sequência recursiva [selecionado pela província de Shandong] (versão 2)

Resumindo

(Por exemplo, questões um e dois, apenas entenda uma solução) O método de aceleração de matriz é primeiro listar a fórmula de recorrência principal (o lado direito deve ser um termo m único) e, em seguida, listar 1 * m e m * m matrizes de acordo com a fórmula, e então é tão simples.

(update2021.3.13) Extensão: Multiplicação de Momento Generalizada

O método acima parece resolver apenas a fórmula recursiva composta por sinais de mais e menos. Na verdade, a fórmula conectada tomando os símbolos máximo e mínimo também pode ser otimizada com uma matriz. Neste momento, a multiplicação generalizada da matriz é usada:

C = A * B, C (i, j) = max / min (A (i, k) + B (k, j)), (Este é apenas um deles)

Pode-se provar que a multiplicação da matriz generalizada ainda satisfaz a lei associativa, mas não satisfaz a taxa de distribuição, mas isso é suficiente, pois a aceleração da matriz necessita apenas da lei associativa.

Por se livrar das restrições dos sinais de mais e menos, a aceleração da matriz pode otimizar muitos problemas aparentemente não otimizados.PD Dinâmico é um algoritmo estabelecido com base na multiplicação generalizada de momentos.

Acho que você gosta

Origin blog.csdn.net/weixin_43960287/article/details/88993370
Recomendado
Clasificación