【CF1119H】Triple
【CF1119H】Triple
题面
题解
有一个想法就是把每一个\(\{a_i,b_i,c_i\}\)写成生成函数\(\text{F}_i\)然后 FWT 起来,再 IFWT 回去发现这样是过不了的。
因为有\(FWT(A\times B)=FWT(A)\times FWT(B)\),
所以 FWT 后所得的结果就是直接把每个 FWT 后再点积起来,即\(FWT(\prod \text F_k)=\prod FWT(\text F_k)[i]=\prod_{j=1}^n(-1)^{|a_j\&i|}x+(-1)^{|b_j\&i|}y+(-1)^{|c_j\&i|}z\),想办法求出\(FWT\)数组。
因为每个项都是\(x,y,z\)加减起来的,但是这样子的话有\(8\)种结果,比较烦,考虑将每个三元组异或上\(a_i\),那么找\(i\)最终答案的项数再异或上一个\(\oplus_i a_i\)即可,三元组就变为\(\{0,a_i\oplus b_i,a_i\oplus c_i\}\)。
那么现在我们只有\(x+y+z,x+y-z,x-y+z,x-y-z\),想办法将四种情况的数目求出来,设对于某个\(i\),四种情况的数目为\(e,f,g,h\),那么显然有\(e+f+g+h=n\)。
如果令\(\text F_k[b_k]=1\),其他项为\(0\),相当于\(x=0,y=1,z=0\),那么最终求出来的结果就是\(y\)前面的系数,即\(y\)系数为正减去\(y\)系数为负的情况,那么有\(e+f-g-h=FWT(\sum\text F_k)[i]\)(\(\sum \text F_k\)在括号里是因为\(FWT(A)+FWT(B)=FWT(A+B)\))
同理可以令\(\text F_k[c_k]=1,a_k=b_k=0\),其他项为\(0\),相当于\(x=0,y=0,z=1\),那么求的是\(z\)前面的系数,有\(e-f+g-h=FWT(\sum\text F_k)[i]\)。
再令\(\text F_k[b_k\oplus c_k]=1\)其他为\(0\),那么就是求的两个的卷积=点值点积即\(\text F_k[i]=(-1)^{|b_j\&i|}(-1)^{|c_j\&i|}\),也是同时考虑\(x,y\)前符号相同\(-\)不同,即\(e-f-g+h=FWT(\sum\text F_k)[i]\)。
把\(e,f,g,h\)解方程解出来就好了,实现细节详见代码。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
using LL = long long;
const int Mod = 998244353, inv2 = (Mod + 1) >> 1;
int fpow(int x, LL y) {
int res = 1;
while (y) {
if (y & 1) res = 1ll * res * x % Mod;
x = 1ll * x * x % Mod;
y >>= 1;
}
return res;
}
const int MAX_N = 1 << 17 | 1;
int N, K, Limit;
void FWT(LL p[]) {
for (int i = 1; i < Limit; i <<= 1)
for (int j = 0; j < Limit; j += i << 1)
for (int k = 0; k < i; k++) {
LL x = p[j + k], y = p[i + j + k];
p[j + k] = x + y, p[i + j + k] = x - y;
}
}
void IFWT(LL p[]) {
for (int i = 1; i < Limit; i <<= 1)
for (int j = 0; j < Limit; j += i << 1)
for (int k = 0; k < i; k++) {
LL x = p[j + k] % Mod, y = p[i + j + k] % Mod;
p[j + k] = 1ll * (x + y) * inv2 % Mod, p[i + j + k] = 1ll * (x - y + Mod) * inv2 % Mod;
}
}
LL F[MAX_N], G[MAX_N], H[MAX_N], A[MAX_N];
int x, y, z;
int sum;
LL s1, s2, s3, s4;
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
scanf("%d %d %d %d %d", &N, &K, &x, &y, &z); Limit = 1 << K;
for (int i = 1; i <= N; i++) {
int a, b, c; scanf("%d %d %d", &a, &b, &c);
sum ^= a, ++F[a ^ b], ++G[a ^ c], ++H[b ^ c];
}
s1 = 1ll * x + y + z, s2 = 1ll * x + y - z, s3 = 1ll * x - y + z, s4 = 1ll * x - y - z;
s1 %= Mod, s2 %= Mod, s3 %= Mod, s4 %= Mod;
FWT(F), FWT(G), FWT(H);
for (int i = 0; i < Limit; i++) {
LL e = (N + F[i] + G[i] + H[i]) >> 2;
LL f = (N + F[i] - 2 * e) >> 1;
LL g = (N + G[i] - 2 * e) >> 1;
LL h = (N + H[i] - 2 * e) >> 1;
A[i] = 1ll * fpow(s1, e) * fpow(s2, f) % Mod * fpow(s3, g) % Mod * fpow(s4, h) % Mod;
}
IFWT(A);
for (int i = 0; i < Limit; i++) printf("%I64d ", (A[i ^ sum] + Mod) % Mod);
putchar('\n');
return 0;
}