[SOJ628]基底畳み込み演習

問題の意味の説明2つの添え字が存在する範囲\([N-0,2 ^)\) レンジ用\([0、M)\ ) 整数のシーケンス\(A、B \) 定義\(C_I = \ MAX_ {J \ OperatorName XOR} {K} I = F(a_j、b_k)\) \(F(X、Y) \) ドメインと範囲[0の両方があり、m )バイナリ整数関数、および\(F(x、y)は 、\) の値が与えられ、検索\(C \) \(N、M \のLeq 16 \)

私は\(\ operatorname {FWT} \)

それ私が偽物!\(\最大\)非還元!だから、\(\ operatorname {ifwt} \ ) ときGUGU区ます!

私は暴力取るよ(10 \)\をポイントに!

彼は、範囲が非常に小さいことに注意し、私たちは維持するように強制することができ\([0、m)を\ ) の各番号が表示されます回。すなわち、我々は、の長さを使用、である\(Mの\)のシーケンス\(F(X、Y) \) シーケンスビット減算の通常の整数の代わりに、通常の整数乗算、加算および減算下畳み込み行わ。

厳密には、前記セット\(A、B、C \ ) の長さ\(m個\)整数のシーケンス、\(C = A \ AST B \ Leftrightarrow C_I = \ sum_ {F(J、K)= I}をa_j \ CDOT b_k \)、\ (C = A BのPM \ \ Leftrightarrow C_I = a_iをPM B_i \ \)

これは楽しいことができます\(\ operatorname {FWT} \ ) それは!得られた\(C_I \)は、整数のシーケンスであり、\(C_ {I、J} \) 代表\(J \)限り、出現数、\(C_ {I、J} \) されていない(0 \ \ )、になります\(\最大\)の拠出を生成します。複雑\(O(N 2 ^ N-CDOT \ CDOT N-M + 2 ^ \ CDOTのM ^ 2)\ \)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
#define R register
#define ll long long
using namespace std;
const int N = 1 << 16, M = 16;

int n, m, lim, f[M][M];
struct node {
    int c[M];
    node() {
        memset(c, 0, sizeof (c));
        return;
    }
    inline node operator * (const node &x) const {
        node ret;
        for (R int i = 0; i < m; ++i)
            for (R int j = 0; j < m; ++j)
                ret.c[f[i][j]] += c[i] * x.c[j];
        return ret;
    }
    inline node operator + (const node &x) const {
        node ret;
        for (R int i = 0; i < m; ++i)
            ret.c[i] = c[i] + x.c[i];
        return ret;
    }
    inline node operator - (const node &x) const {
        node ret;
        for (R int i = 0; i < m; ++i)
            ret.c[i] = c[i] - x.c[i];
        return ret;
    }
}a[N], b[N], c[N];

template <class T> inline void read(T &x) {
    x = 0;
    char ch = getchar(), w = 0;
    while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    x = w ? -x : x;
    return;
}

void fwt(node *a, int lim, int opt) {
    int n = 1 << lim;
    for (R int l = 2; l <= n; l <<= 1)
        for (R int m = l >> 1, i = 0; i < n; i += l)
            for (R int j = i; j < i + m; ++j)
                if (opt == 1)
                    a[j + m] = a[j + m] + a[j];
                else
                    a[j + m] = a[j + m] - a[j];
    return;
}

int main() {
    int x;
    read(n), read(m), lim = 1 << n;
    for (R int i = 0; i < lim; ++i)
        read(x), a[i].c[x] = 1;
    for (R int i = 0; i < lim; ++i)
        read(x), b[i].c[x] = 1;
    for (R int i = 0; i < m; ++i)
        for (R int j = 0; j < m; ++j)
            read(f[i][j]);
    fwt(a, n, 1), fwt(b, n, 1);
    for (R int i = 0; i < lim; ++i)
        c[i] = a[i] * b[i];
    fwt(c, n, -1);
    for (R int i = 0; i < lim; ++i) {
        for (R int j = m - 1; ~j; --j)
            if (c[i].c[j]) {
                printf("%d ", j);
                break;
            }
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/suwakow/p/11640852.html