Séries de Potência sobre Conjuntos

Séries de Potência sobre Conjuntos

Conceito Básico

Considere um conjunto universo \(U = \{1, 2, \ldots, n\}\) e \(2^U\) como sua coleção de subconjuntos. Dada uma função \(f : 2^U \rightarrow \mathbb{R}\), a série de potência sobre conjuntos relacionada é definida como:

Operações Elementares

A adição segue o comportamento usual de séries de potência, com coeficientes somados de forma direta. A multiplicação, contudo, exige que coeficientes sejam multiplicados e índices combinados através de operações binárias (\(\oplus\)):

Em situações práticas, estados são frequentemente expressos em representação binária, dando destaque à convolução por operações bit-a-bit como cenário aplicável.

Operações sobre Subconjuntos

Somas e Diferenças Multidimensionais

Somas sobre superconjuntos ou subconjuntos podem ser computadas de forma eficiente. A versão para prefixos (subconjuntos) obedece ao algoritmo:

// Soma para subconjuntos
for(int bit = 0; bit < n; bit++) {
    for(int mask = 0; mask < (1 << n); mask++) {
        if(mask & (1 << bit)) sum[mask] += sum[mask ^ (1 << bit)];
    }
}

// Soma para superconjuntos
for(int bit = 0; bit < n; bit++) {
    for(int mask = 0; mask < (1 << n); mask++) {
        if(!(mask & (1 << bit))) sum[mask] += sum[mask | (1 << bit)];
    }
}

As operações inversas (diferenças) seguem uma adaptação semelhente:

// Subtração para subconjuntos
for(int bit = 0; bit < n; bit++) {
    for(int mask = 0; mask < (1 << n); mask++) {
        if(mask & (1 << bit)) diff[mask] -= diff[mask ^ (1 << bit)];
    }
}

// Subtração para superconjuntos
for(int bit = 0; bit < n; bit++) {
    for(int mask = 0; mask < (1 << n); mask++) {
        if(!(mask & (1 << bit))) diff[mask] -= diff[mask | (1 << bit)];
    }
}

Transformação Rápida de Möbius (FMT)

Convolução OU (União)

Define-se \(\widehat{f}_S = \sum_{T \subseteq S} f_T\). A convolução para união é dada por \(\widehat{h}_S = \widehat{f}_S \cdot \widehat{g}_S\), seguida da FMT inversa (FMI).

Convolução E (Interseção)

Para interseção, itera-se sobre superconjuntos: \(\widehat{f}_S = \sum_{S \subseteq T} f_T\), resultando em \(\widehat{h}_S = \widehat{f}_S \cdot \widehat{g}_S\).

int modulo = 1000000007;

void aplicar_FMT_OU(int* arranjo, int sinal) {
    for(int bit = 0; bit < n; bit++) {
        for(int mask = 0; mask < (1 << n); mask++) {
            if(mask & (1 << bit)) 
                arranjo[mask] = (arranjo[mask] + sinal * arranjo[mask ^ (1 << bit)]) % modulo;
        }
    }
}

void aplicar_FMT_E(int* arranjo, int sinal) {
    for(int bit = 0; bit < n; bit++) {
        for(int mask = 0; mask < (1 << n); mask++) {
            if(!(mask & (1 << bit))) 
                arranjo[mask] = (arranjo[mask] + sinal * arranjo[mask | (1 << bit)]) % modulo;
        }
    }
}

Transformação Rápida de Walsh (FWT)

Convolução XOR (Diferença Simétrica)

A transformação é explicitada na forma:

void transformar_FWT_XOR(int* arranjo, bool inverso) {
    int dimensao = 1 << n;
    for(int delta = 1; delta < dimensao; delta *= 2) {
        for(int idx = 0; idx < dimensao; idx += 2 * delta) {
            for(int k = 0; k < delta; k++) {
                int a = arranjo[idx + k];
                int b = arranjo[idx + delta + k];
                arranjo[idx + k] = (a + b) % modulo;
                arranjo[idx + delta + k] = (a - b + modulo) % modulo;
            }
        }
    }
    if(inverso) {
        int factor_inverso = potencia_modular(1 << n, modulo - 2, modulo);
        for(int idx = 0; idx < dimensao; idx++) {
            arranjo[idx] = 1LL * arranjo[idx] * factor_inverso % modulo;
        }
    }
}

Convolução Limitada por Cardinalidade

Introduz-se a condição adicional \(|A| + |B| = |C|\) para sbuconjuntos disjuntos na operação:

int contar_bits(int valor) {
    return __builtin_popcount(valor);
}

void convolucionar_subconjunto() {
    int padrao_max = (1 << n);
    for(int i = 0; i <= n; i++) {
        aplicar_FMT_OU(arranjo_F[i], 1);
        aplicar_FMT_OU(arranjo_G[i], 1);
    }
    for(int soma_cards = 0; soma_cards <= n; soma_cards++) {
        for(int mask = 0; mask < padrao_max; mask++) {
            for(int card_A = 0; card_A <= soma_cards; card_A++) {
                int card_B = soma_cards - card_A;
                arranjo_H[soma_cards][mask] = (arranjo_H[soma_cards][mask] + 
                    1LL * arranjo_F[card_A][mask] * arranjo_G[card_B][mask]) % modulo;
            }
        }
    }
    for(int i = 0; i <= n; i++) {
        aplicar_FMT_OU(arranjo_H[i], -1);
    }
}

Tags: série_potência convolução fmt FWT Conjuntos

Publicado em 9-19 12:13