E - 料理の順番 / Order of Dishes Editorial by admin
gemini-3.5-flash-thinkingOverview
This is a problem where you make some dishes out of \(N\) types in a feasible order that does not violate any failure conditions, and maximize the total satisfaction obtained. By focusing on the constraint \(N \le 19\), we can solve this efficiently within the time limit by combining Bit DP with the Sum Over Subsets DP (SOS DP, also known as the fast zeta transform).
Analysis
Naive Approach and Its Limitations
A naive method of trying all possible orderings of dishes (exhaustive permutation search) has a time complexity of \(O(N!)\). For \(N=19\), since \(19! \approx 1.2 \times 10^{17}\), this is infeasible.
Next, consider determining which dish \(p \notin U\) can be made next, given that the set of already completed dishes is \(U\). Dish \(p\) cannot be made (fails) when there exists a failure condition \((p, S)\) such that \(S \subseteq U\). If we try to determine this naively, for each state \(U\) (\(2^N\) possibilities), we need to check all \(M\) failure conditions, resulting in a time complexity of \(O(M 2^N)\). This requires approximately \(10^5 \times 5 \times 10^5 \approx 5 \times 10^{10}\) operations, which also exceeds the time limit.
Approach to the Solution: Using the Fast Zeta Transform
To solve this problem, we consider precomputing “the set of dishes \(F(U)\) that cannot be made next, given the set of already completed dishes \(U\)” all at once efficiently.
By definition, the set of forbidden dishes \(F(U)\) for a set \(U\) can be expressed as: $\(F(U) = \bigcup_{S \subseteq U} \{ p \mid (p, S) \text{ is a failure condition} \}\)$
This reduces to the problem of computing the union (OR) over subsets, with the initial value for each \(S\) being “the set of directly forbidden dishes” (let’s call this forbidden[S]).
$\(F(U) = \bigcup_{S \subseteq U} \text{forbidden}[S]\)$
This type of computation can be performed for all \(U\) simultaneously in \(O(N 2^N)\) using the fast zeta transform (SOS DP: Sum Over Subsets DP). Once this is computed, the dishes that can be made next from state \(U\) are those that: - Have not been made yet (\(\notin U\)) - And are not forbidden (\(\notin F(U)\))
This can be determined and transitioned in \(O(1)\) using bitwise operations.
Algorithm
1. Initialization of Failure Conditions
Prepare an array forbidden of length \(2^N\).
For each failure condition \((p, S)\), set the \(p\)-th bit of forbidden[S] to \(1\).
2. Propagation of Forbidden Sets via Fast Zeta Transform
Perform the fast zeta transform to compute \(F(U) = \bigcup_{S \subseteq U} \text{forbidden}[S]\) for all \(U\).
Specifically, for each dimension (dish \(i = 0, \dots, N-1\)), OR the value of a set sub that does not contain dish \(i\) into the set sub + (1 << i) that contains dish \(i\).
3. Computing the Sum of Satisfaction for Each Set
Similarly, precompute the total satisfaction A_sum[U] obtained when making the set of dishes \(U\), using the fast zeta transform (with addition this time) in \(O(N 2^N)\).
4. Finding the Maximum via Bit DP
Perform DP where dp[mask] represents “whether it is possible to complete the set of dishes mask in a feasible order (True/False)”.
- Initial value:
dp[0] = True - Transition: When
dp[mask]isTrue, compute the set of candidate dishesvalidthat can be made next using bitwise operations:valid = all_mask & ~(forbidden[mask] | mask)(The universal set minus “already made dishesmask” and “currently forbidden dishesforbidden[mask]”) - For each dish \(p\) in
valid, updatedp[mask | (1 << p)] = True. - The answer is the maximum value of
A_sum[mask]over allmaskwheredp[mask]isTrue.
Complexity
Time complexity: \(O(N 2^N + M)\)
- Input and initialization of failure conditions: \(O(M)\)
- Fast zeta transform for
forbidden: \(O(N 2^N)\) - Fast zeta transform for
A_sum: \(O(N 2^N)\) - DP transitions: For each
mask, the loop runs for the number of dishes that can be transitioned to next (at most \(N\)), so the worst case is \(O(N 2^N)\). - When \(N = 19\), \(N 2^N \approx 19 \times 5.2 \times 10^5 \approx 10^7\), which runs sufficiently fast even in Python.
Space complexity: \(O(2^N)\)
- The size of each array
forbidden,A_sum, anddpis \(2^N\). - When \(N = 19\), this is \(2^{19} = 524,288\) elements, and memory consumption is on the order of a few MB to tens of MB, which is very safe with respect to the memory limit.
- The size of each array
Implementation Key Points
Speedup via bitwise operations: When enumerating the set bits in
valid(dishes that can be made next) during DP transitions, we use the trickp = valid & -valid(extracting the lowest set bit) andvalid ^= pto process only as many iterations as there are set bits (= number of transition targets), achieving efficient processing.Converting from 1-indexed to 0-indexed: The dish numbers in the input range from \(1\) to \(N\), but to perform bitwise operations smoothly, the code decrements them to range from \(0\) to \(N-1\).
Source Code
import sys
def solve():
input_data = sys.stdin.read().split()
if not input_data:
return
N = int(input_data[0])
M = int(input_data[1])
A = [int(x) for x in input_data[2:2+N]]
forbidden = [0] * (1 << N)
idx = 2 + N
for _ in range(M):
p = int(input_data[idx]) - 1
c = int(input_data[idx+1])
mask_S = 0
for j in range(c):
mask_S |= 1 << (int(input_data[idx+2+j]) - 1)
forbidden[mask_S] |= 1 << p
idx += 2 + c
# 高速ゼータ変換 (Superset OR)
for i in range(N):
bit = 1 << i
for mask in range(0, 1 << N, bit << 1):
for sub in range(mask, mask + bit):
forbidden[sub + bit] |= forbidden[sub]
# A_sum の計算
A_sum = [0] * (1 << N)
for i in range(N):
bit = 1 << i
val = A[i]
for mask in range(0, 1 << N, bit << 1):
for sub in range(mask, mask + bit):
A_sum[sub + bit] = A_sum[sub] + val
# DP
dp = [False] * (1 << N)
dp[0] = True
ans = 0
all_mask = (1 << N) - 1
for mask in range(1 << N):
if not dp[mask]:
continue
if A_sum[mask] > ans:
ans = A_sum[mask]
valid = all_mask & ~(forbidden[mask] | mask)
while valid:
p = valid & -valid
dp[mask | p] = True
valid ^= p
print(ans)
if __name__ == '__main__':
solve()
This editorial was generated by gemini-3.5-flash-thinking.
posted:
last update: