Resolução de Equações com Aritmética Modular e Algoritmo de Qin Jiushao

Pré-requisitos

Para uma variável (x) e um módulo (p), se definimos (x = kp + b), então (x \equiv b ,(\mod p)), e simultaneamente (f(x) \equiv f(b) ,(\mod p)).

A partir disso, podemos concluir que: sob o módulo p, uma condição necessária para (f(x) = 0) é que (f(x \mod p) = 0). Quando o módulo é suficientemente grande ou consideramos múltiplos módulos, se (f(x \mod p) = 0), é muito provável que (f(x) = 0) seja verdadeiro (similar a uma tabela de hash).

Algoritmo de Qin Jiushao

Em geral, a avaliação de um polinômio de grau n requer ((n+1) \times n \div 2) multiplicações e (n) adições. O algoritmo de Qin Jiushao, por outro lado, necessita apenas de (n) multiplicações e (n) adições, simplificando significativamente o processo de cálculo.

Um polinômio de grau (n):

[f(x) = a_0 + a_1x^1 + \ldots + a_{n-1}x^{n-1} + a_nx^n]

pode ser reescrito na forma:

[\begin{aligned} f(x) &= a_0 + a_1x + \ldots + a_{n-1}x^{n-1} + a_nx^n \ &= a_nx^n + a_{n-1}x^{n-1} + \ldots + a_1x + a_0 \ &= (a_nx^{n-1} + a_{n-1}x^{n-2} + \ldots + a_2x + a_1)x + a_0 \ &= ((a_nx^{n-2} + a_{n-1}x^{n-3} + \ldots + a_3x + a_2)x + a_1)x + a_0 \ &\vdots \ &= (\ldots((a_nx + a_{n-1})x + a_{n-2})x + \ldots + a_1)x + a_0 \end{aligned}]

Implementação do Algoritmo de Qin Jiushao

#include <iostream>
#include <vector>
using namespace std;

const int MAX_GRAU = 1001;

int main() {
    int grau, valor, modulo;
    cin >> grau >> valor >> modulo;
    
    vector<int> coeficientes(grau + 1);
    
    // Lê os coeficientes do polinômio
    for (int i = 0; i <= grau; i++) {
        cin >> coeficientes[i];
    }
    
    // Aplica o algoritmo de Qin Jiushao
    int resultado = coeficientes[grau];
    for (int i = grau - 1; i >= 0; i--) {
        resultado = (resultado * valor + coeficientes[i]) % modulo;
    }
    
    cout << resultado << endl;
    return 0;
}

Aplicação Prática

Vamos resolver um problmea específico usando esses conceitos. O objetivo é encontrar todas as raízes inteiras de um polinômio dentro de um determinado intervalo.

#include <iostream>
#include <vector>
using namespace std;

const int MODULO_PRIMO = 1000000007;
const int MAX_GRAU = 101;

vector<int> coeficientes(MAX_GRAU);

// Função para ler números eficientemente
void lerCoeficiente(int posicao) {
    long long num = 0, sinal = 1;
    char caractere;
    
    while (true) {
        caractere = getchar();
        if (caractere >= '0' && caractere <= '9') {
            num = (num * 10 + (caractere - '0')) % MODULO_PRIMO;
        } else if (caractere == '-') {
            sinal = -1;
        } else {
            break;
        }
    }
    
    coeficientes[posicao] = num * sinal;
}

int main() {
    int grau, limite_superior;
    cin >> grau >> limite_superior;
    
    // Lê todos os coeficientes do polinômio
    for (int i = 0; i <= grau; i++) {
        lerCoeficiente(i);
    }
    
    vector<int> raizes;
    int contador_raizes = 0;
    
    // Testa cada valor no intervalo
    for (int x = 1; x <= limite_superior; x++) {
        long long valor_resultante = coeficientes[grau] % MODULO_PRIMO;
        
        // Aplica o algoritmo de Qin Jiushao
        for (int j = grau - 1; j >= 0; j--) {
            valor_resultante = (valor_resultante * x + coeficientes[j]) % MODULO_PRIMO;
        }
        
        // Se o resultado for zero, encontramos uma raiz
        if (valor_resultante == 0) {
            contador_raizes++;
            raizes.push_back(x);
        }
    }
    
    // Exibe os resultados
    cout << contador_raizes << endl;
    for (int raiz : raizes) {
        cout << raiz << endl;
    }
    
    return 0;
}

Tags: aritmética modular algoritmo de Qin Jiushao Polinômios Programação Competitiva C++

Publicado em 6-21 21:41