E - アレルギー検査 / Allergy Test Editorial by admin
GPT 5.2 HighOverview
We count the number of allergen (causative substance) sets modulo \(998244353\) that simultaneously satisfy “all ingredients eaten by monitors with no reaction (0) are safe” and “each monitor with a reaction (1) contains at least one causative substance.”
Using the constraint \(M \le 20\), we perform the counting all at once with inclusion-exclusion principle and fast zeta transform (subset sum DP).
Analysis
Key Observation 1: Ingredients contained in monitors with \(R_j=0\) are “forced to be safe”
If monitor \(j\) has no reaction (\(R_j=0\)), then not a single allergen can exist in the set \(S_j\).
Therefore, if an ingredient is contained in even one monitor with \(R=0\), that ingredient must be safe (it can be excluded from consideration).
In the code, for each ingredient \(i\), we store “which monitors’ sets it belongs to” as a bitmask ing_mask[i].
If ing_mask[i] & negMask != 0 (where negMask is the set of monitors with \(R=0\)), then that ingredient is discarded (forced safe).
Key Observation 2: For remaining ingredients, only “which reaction-positive monitors they can satisfy” matters
Monitors with \(R=1\) (hereafter “positive monitors”) each require “at least one allergen in their set \(S_j\).”
So we extract only the positive monitors (count \(p \le 20\)), and compress each ingredient into
- a \(p\)-bit mask representing “which positive monitors contain it”
(this is reduced in the code).
Ingredients with the same reduced value are completely equivalent with respect to this condition, so it suffices to just count them (freq[mask]).
Why a naive approach doesn’t work
- There can be up to \(N=2\times 10^5\) ingredients, so exhaustive search over \(2^N\) is impossible.
- However, there are at most \(20\) monitors, so an approach that iterates over the monitor side (condition side) in \(2^M\) time is feasible.
Solution: Count “all satisfied” using inclusion-exclusion
The condition that all positive monitors are satisfied (each person has at least one allergen) can be counted using inclusion-exclusion on the negation “there exists someone who is not satisfied.”
Algorithm
Let the number of positive monitors be \(p\), and the full set be \(U=\{0,1,\dots,p-1\}\).
1. Removal of forced-safe ingredients and mask compression
- Let
negMaskbe the set of monitors with \(R_j=0\). - For each ingredient \(i\), construct
ing_mask[i]representing the set of monitors it appears in. - If
ing_mask[i] & negMask != 0, the ingredient is forced safe, so ignore it. - For remaining ingredients, extract only the positive monitor bits and compress into a \(p\)-bit mask called
reduced, then incrementfreq[reduced]++.- Let \(K\) be the number of remaining ingredients (candidates that can freely be made into allergens).
2. Form of the inclusion-exclusion
For a subset \(T \subseteq U\) of positive monitors, we count the situations where “all members of \(T\) are not satisfied (= no allergen is in their set).”
For none of the monitors in \(T\) to be satisfied, the allergen ingredients we choose must not be contained in any monitor in \(T\).
In other words, only ingredients whose mask satisfies \(mask \cap T = \emptyset\) can be chosen as allergens.
Let \(g(T)\) be the count of such ingredients. Then the number of allergen sets where “all of \(T\) are unsatisfied” is $\( 2^{g(T)} \)\( (we simply choose freely from those \)g(T)$ ingredients).
Therefore, by inclusion-exclusion, the answer is $\( \text{ans} = \sum_{T \subseteq U} (-1)^{|T|}\, 2^{g(T)} \)$
3. Computing \(g(T)\) for all \(T\) efficiently (zeta transform)
Given freq[mask],
$\(
g(T) = \sum_{\substack{mask \subseteq U \\ mask \cap T=\emptyset}} freq[mask]
= \sum_{mask \subseteq (U \setminus T)} freq[mask]
\)$
If we can compute $\( F[X] = \sum_{sub \subseteq X} freq[sub] \)\( for all \)X\(, then \)\( g(T) = F[U \setminus T] \)$ can be obtained immediately.
This \(F\) can be computed in \(O(p2^p)\) using “fast zeta transform (subset sum DP)” (the in-place transformation part of the code).
Finally, for each \(T\), we set g = F[allmask ^ T] and add/subtract \((-1)^{|T|} 2^g\).
Complexity
- Time complexity:
- Input processing and mask construction: \(O\!\left(\sum k_j\right)\)
- Mask compression (iterating over set bits of each ingredient): at most \(O(NM)\), but sufficiently fast since \(M \le 20\)
- Zeta transform: \(O(p2^p)\) (at most about \(2.0\times 10^7\) operations since \(p \le 20\))
- Inclusion-exclusion summation: \(O(2^p)\)
Overall: \(O\!\left(\sum k_j + p2^p\right)\).
- Input processing and mask construction: \(O\!\left(\sum k_j\right)\)
- Space complexity: \(O(N + 2^p)\)
Implementation Notes
Applying “all ingredients that appeared in reaction-0 monitors are safe” first means we only need to look at positive monitors afterwards, drastically reducing the problem size.
Overwriting
freqin-place with the zeta transform to use asFsaves memory.Since \(2^{g(T)}\) is used many times, we precompute
pow2[i]=2^i mod MODup to \(K\).Even when \(p=0\) (no monitors with a reaction), the formula works naturally, and the answer becomes \(2^K\) (free ingredients can be freely made into allergens).
Source Code
import sys
MOD = 998244353
data = sys.stdin.buffer.read()
n_data = len(data)
ptr = 0
def next_int():
global ptr
while ptr < n_data and data[ptr] <= 32:
ptr += 1
v = 0
while ptr < n_data and data[ptr] > 32:
v = v * 10 + (data[ptr] - 48)
ptr += 1
return v
N = next_int()
M = next_int()
ing_mask = [0] * N
for j in range(M):
k = next_int()
bit = 1 << j
for _ in range(k):
x = next_int() - 1
ing_mask[x] |= bit
R = [next_int() for _ in range(M)]
negMask = 0
pos_indices = []
for j, r in enumerate(R):
if r == 0:
negMask |= 1 << j
else:
pos_indices.append(j)
p = len(pos_indices)
posMask = 0
posToIdx = [-1] * M
for idx, j in enumerate(pos_indices):
posMask |= 1 << j
posToIdx[j] = idx
L = 1 << p
freq = [0] * L
K = 0
for om in ing_mask:
if om & negMask:
continue
m = om & posMask
reduced = 0
while m:
b = m & -m
j = b.bit_length() - 1
reduced |= 1 << posToIdx[j]
m -= b
freq[reduced] += 1
K += 1
pow2 = [1] * (K + 1)
for i in range(1, K + 1):
pow2[i] = (pow2[i - 1] * 2) % MOD
f = freq # in-place zeta transform: f[U] = sum_{sub ⊆ U} freq[sub]
for i in range(p):
step = 1 << i
jump = step << 1
for base in range(0, L, jump):
start = base + step
end = base + jump
for m in range(start, end):
f[m] += f[m - step]
allmask = L - 1
ans = 0
for T in range(L):
g = f[allmask ^ T] # count of items with (mask & T) == 0
term = pow2[g]
if T.bit_count() & 1:
ans -= term
if ans < 0:
ans += MOD
else:
ans += term
if ans >= MOD:
ans -= MOD
print(ans)
This editorial was generated by gpt-5.2-high.
posted:
last update: