問題の意味の説明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;
}