题解:P13275 [NOI2025] 集合
WorldMachine · · 题解
好难啊。
设
元素的交集恰好为
代入原式:
发现两个
这时候
考虑后面那一坨东西是在干什么,设
考虑每个
因此原式化为:
不妨设
进一步地,观察所求式的结构,不难想到设
这是一个 OR 卷积的形式,直接上 FWT 即可。
但这样做有一个问题:分母上出现了
因此需要记录每个数乘/除了多少个
#include <bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar_unlocked()
il int rd() { int x = 0; char c = 0; while (c < '0' || c > '9') c = gc; while (c >= '0' && c <= '9') x = x * 10 - '0' + c, c = gc; return x; }
typedef long long ll;
const int N = 1 << 20 | 5, p = 998244353, inv2 = p + 1 >> 1;
int task_id, T, ppc[N], invpw2[21], _n, n, a[N];
int qpow(int a, int b) { int c = 1; while (b) { if (b & 1) c = (ll)c * a % p; a = (ll)a * a % p, b >>= 1; } return c; }
struct num { int x, z; num(int a = 0) { if (a) x = a, z = 0; else x = 1, z = 1; } num(int x, int z): x(x), z(z) {} } A[N], B[N], invB[N], C[N], D[N], E[N];
il num operator+(num a, num b) { return a.z == b.z ? num((a.x + b.x) % p, a.z) : (a.z < b.z ? a : b); }
il num operator-(num a, num b) { return a.z == b.z ? num((a.x - b.x + p) % p, a.z) : (a.z < b.z ? a : num((p - b.x) % p, b.z)); }
il num operator*(num a, num b) { return num((ll)a.x * b.x % p, a.z + b.z); }
il num inv(num a) { return num(qpow(a.x, p - 2), -a.z); }
il num operator/(num a, num b) { return a * inv(b); }
void sufmul(num a[]) {
for (int i = 0; i < _n; i++) {
for (int j = 0; j < n; j++) if (!(j >> i & 1)) a[j] = a[j] * a[j ^ 1 << i];
}
}
void FWT(num a[]) {
for (int i = 0; i < _n; i++) {
for (int j = 0; j < n; j++) if (j >> i & 1) a[j] = a[j] + a[j ^ 1 << i];
}
}
void iFWT(num a[]) {
for (int i = _n - 1; ~i; i--) {
for (int j = 0; j < n; j++) if (j >> i & 1) a[j] = a[j] - a[j ^ 1 << i];
}
}
void solve() {
_n = rd(), n = 1 << _n;
for (int i = 0; i < n; i++) a[i] = rd(), A[i] = num((a[i] << 1 | 1) % p), B[i] = num((a[i] + 1) % p);
sufmul(A), sufmul(B);
for (int i = 0; i < n; i++) invB[i] = inv(B[i]);
for (int i = 0; i < n; i++) C[i] = A[i] * invB[i] * invB[i] * invpw2[ppc[i]];
for (int i = 0; i < n; i++) D[i] = B[i] * (1 << ppc[i]) * (ppc[i] & 1 ? p - 1 : 1);
FWT(D);
for (int i = 0; i < n; i++) E[i] = D[i] * D[i];
iFWT(E);
int ans = 0;
for (int i = 0; i < n; i++) {
num x = C[i] * E[i];
if (!x.z) ans = (ans + x.x) % p;
}
cout << ans << '\n';
}
int main() {
// freopen("set.in", "r", stdin), freopen("set.out", "w", stdout);
for (int i = 1; i < N; i++) ppc[i] = ppc[i ^ (i & -i)] + 1;
invpw2[0] = 1; for (int i = 1; i <= 20; i++) invpw2[i] = (ll)invpw2[i - 1] * inv2 % p;
task_id = rd(), T = rd(); while (T--) solve();
}