E - 展示会の配置 / Exhibition Layout Editorial by admin Editorial for printing
(Not recommended)GPT 5.2 HighOverview
We determine a permutation that arranges paintings from left to right, and maximize the total sum of the color tone difference \(|P_a-P_b|\) between adjacent paintings multiplied by the wall weight \(W_i\). Since \(N\le 16\), we use dynamic programming with sets (bitmasks) to find the maximum value by processing “from left to right.”
Analysis
Key Observation
The evaluation value is [ \sum{i=1}^{N-1} |P{Qi}-P{Q_{i+1}}|\times W_i ] and each term is determined solely by “the two paintings placed at positions \(i\) and \(i+1\)” and “the wall weight \(W_i\) between them.”
In other words, when placing paintings from left to right: - We have already placed \(k\) paintings (positions \(1\sim k\) are determined) - We decide which painting to place as the \((k+1)\)-th
The increase in evaluation is the difference between “the last painting” and “the next painting” multiplied by \(W_k\) (since the boundary is between positions \(k\) and \(k+1\), the weight is \(W_k\)).
Why the Naive Approach Fails
Trying all permutations gives \(N!\) possibilities, and for \(N=16\): [ 16!\approx 2.1\times 10^{13} ] which is far too many for brute force.
How to Solve It
By managing “which paintings have been used” as a set and additionally keeping track of “the last painting placed” as part of the state, we can: - Among all paths that reach the same set and same last painting, keep only the one with the maximum evaluation value
This compresses the search space (a classic bitDP / Traveling Salesman-type DP).
Algorithm
State Definition
Let the bitmask \(\text{mask}\) represent “the set of paintings already placed” (the \(i\)-th bit is 1 if painting \(i\) has been used).
[ dp[\text{mask}][\text{last}] ] is defined as follows:
- The paintings in \(\text{mask}\) have been arranged from the left, with \(k=\mathrm{popcount}(\text{mask})\) paintings placed
- The rightmost painting (at position \(k\)) is
last - The maximum evaluation value achieved so far
Initialization — when only one painting is placed, the evaluation is 0: [ dp[1\ll i][i]=0 ]
Transition
Let \(k=\mathrm{popcount}(\text{mask})\) be the size of \(\text{mask}\). The next painting is placed at position \(k+1\). The increase in evaluation comes from the boundary between positions \(k\) and \(k+1\), so the weight is \(W_k\) (in 1-indexed \(W_{k}\), or W[k-1] in a 0-indexed array).
For nxt being an unused painting:
[
dp[\text{mask}\cup{nxt}][nxt]
\max\Big( dp[\text{mask}\cup{nxt}][nxt],\; dp[\text{mask}][last] + |P{last}-P{nxt}|\times W_k \Big) ]
In the code, since we are transitioning from a state with \(k\) paintings placed, we use weight = W[k-1] (due to 0-indexing).
Answer
For the full mask \(\text{full}=(1\ll N)-1\): [ \max_{last} dp[\text{full}][last] ] is the answer (we take the maximum over all possible last paintings).
Implementation Tips
- Since \(|P_i-P_j|\) is used frequently, precompute all values as
dist[i][j]. - To enumerate unused paintings, extract the lowest set bit using
r & -rfor efficient iteration.
Complexity
- Time complexity: \(O(N^2 2^N)\)
(The number of states is \(N2^N\), with up to \(N\) transitions from each state) - Space complexity: \(O(N2^N)\)
(DP table)
Implementation Notes
Pay attention to the boundary weight correspondence: when transitioning from a state with \(k\) paintings placed, the weight used is “between positions \(k\) and \(k+1\),” which corresponds to
W[k-1]in a 0-indexed array.Managing unreached states as
Noneindpand branching duringmaxupdates is a safe approach.In Python,
mask.bit_count()is fast and works very well with bitDP for \(N\le16\).Source Code
import sys
def main():
input = sys.stdin.readline
N = int(input())
P = list(map(int, input().split()))
W = list(map(int, input().split()))
full = (1 << N) - 1
dist = [[0] * N for _ in range(N)]
for i in range(N):
pi = P[i]
for j in range(N):
dist[i][j] = abs(pi - P[j])
dp = [[None] * N for _ in range(1 << N)]
for i in range(N):
dp[1 << i][i] = 0
for mask in range(1 << N):
k = mask.bit_count()
if k == 0 or k == N:
continue
weight = W[k - 1]
rem = full ^ mask
row = dp[mask]
for last in range(N):
val = row[last]
if val is None:
continue
r = rem
dlast = dist[last]
while r:
lsb = r & -r
nxt = lsb.bit_length() - 1
nmask = mask | lsb
nv = val + dlast[nxt] * weight
cur = dp[nmask][nxt]
if cur is None or nv > cur:
dp[nmask][nxt] = nv
r -= lsb
ans = max(v for v in dp[full] if v is not None)
print(ans)
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.2-high.
posted:
last update: