結果
| 問題 |
No.284 門松と魔法(2)
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:10:43 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 10,664 bytes |
| コンパイル時間 | 419 ms |
| コンパイル使用メモリ | 82,688 KB |
| 実行使用メモリ | 181,420 KB |
| 最終ジャッジ日時 | 2025-05-14 13:12:13 |
| 合計ジャッジ時間 | 10,297 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 23 TLE * 1 -- * 16 |
ソースコード
import sys
# Set higher recursion depth for safety, though iterative segment tree should be fine.
# sys.setrecursionlimit(200000)
def solve():
N = int(sys.stdin.readline())
# Handle cases where N is too small to form a valid sequence of length >= 3.
# The problem defines valid sequences as M=0 or M>=3 satisfying conditions.
# Any sequence of length 1 or 2 is not valid according to this problem statement structure.
# Thus, if N <= 2, the maximum possible valid length is 0.
if N <= 2:
# Consume the second line (array elements) if N > 0, as it's provided but not needed.
if N > 0:
sys.stdin.readline()
print(0)
return
# Read the bamboo heights
A = list(map(int, sys.stdin.readline().split()))
# Coordinate compression: Map original heights to ranks [0, D-1]
# This is useful for using data structures like segment trees where array indices are needed.
# Get unique sorted values
coords = sorted(list(set(A)))
# Create a dictionary mapping each height to its rank
rank = {val: i for i, val in enumerate(coords)}
# D is the number of distinct heights
D = len(coords)
# Segment Tree Implementation
# Supports Range Maximum Query and Point Update operations.
# Uses an iterative approach for potentially better performance and avoiding deep recursion.
class SegmentTree:
def __init__(self, size):
# Calculate the smallest power of 2 greater than or equal to size for the tree array
self.actual_size = 1
while self.actual_size < size:
self.actual_size <<= 1
# Initialize data array with 0s. Array size is 2 * power_of_2.
self.data = [0] * (2 * self.actual_size)
# Update leaf k (0-indexed) with value x.
# This update assumes we want to store the maximum length found so far for this state.
# So we only update if the new value x is greater than the existing value.
def update(self, k, x):
# Map k to the leaf index in the segment tree array
k += self.actual_size
# Optimization: If the new value is not greater, no update needed.
if x <= self.data[k]:
return
self.data[k] = x
# Propagate the change upwards to parent nodes
while k > 1:
# Parent node (k >> 1) stores the maximum of its children (k and k ^ 1)
new_max = max(self.data[k], self.data[k ^ 1])
# Optimization: If parent value doesn't change, stop propagation.
if self.data[k >> 1] == new_max:
break
self.data[k >> 1] = new_max
k >>= 1
# Query maximum value in the range [l, r) (0-indexed, exclusive of r)
def query(self, l, r):
# Handle invalid or empty range queries
if l >= r:
return 0
# Map range [l, r) to segment tree array indices
L = l + self.actual_size; R = r + self.actual_size
s = 0 # Initialize maximum value found to 0
# Iteratively traverse up the tree from leaves L and R
while L < R:
# If R is the right child, include its sibling node's range and move R left
if R & 1:
R -= 1
s = max(s, self.data[R])
# If L is the left child, include its value and move L right to its sibling
if L & 1:
s = max(s, self.data[L])
L += 1
# Move up to the parent level
L >>= 1; R >>= 1
return s
# Store segment trees for each index k. segment_trees[k] will hold a tuple (ST_up_k, ST_down_k).
# ST_up_k stores max dp_up[j][k] (length ending j,k with A[j]<A[k]) indexed by rank(A[j]).
# ST_down_k stores max dp_down[j][k] (length ending j,k with A[j]>A[k]) indexed by rank(A[j]).
# Note: This list could potentially consume large memory if N and D are large.
segment_trees = [None] * N
# Variable to keep track of the maximum valid sequence length found so far (must be >= 3).
max_len = 0
# Iterate through each element A[k] which acts as the potential last element of a subsequence.
for k in range(N):
# Initialize segment trees for the current index k.
# These trees will store information about sequences ending at index k.
st_up_k = SegmentTree(D)
st_down_k = SegmentTree(D)
A_k = A[k] # Height of the current last element
rank_A_k = rank[A_k] # Rank of the height A[k]
# Iterate through each element A[j] (where j < k) which acts as the potential second to last element.
for j in range(k):
A_j = A[j] # Height of the second to last element
rank_A_j = rank[A_j] # Rank of the height A[j]
# Check if A_j and A_k are identical.
# A valid sequence requires distinct adjacent elements for the condition check (B_i != B_{i+1} implied).
# Also, the triplet condition (B_{i-1}, B_i, B_{i+1}) requires all three heights to be distinct.
# If A_j == A_k, this pair cannot be the last two elements of a valid sequence of length >= 3.
if A_j == A_k:
continue # Skip this pair (j, k)
# The base length for any pair (A_j, A_k) with A_j != A_k is 2.
# This represents a potential starting point for a longer sequence.
current_base_len = 2
# Initialize DP values for the current pair (j, k)
current_dp_up = 0 # Max length ending A_j, A_k where A_j < A_k (A_k is peak relative to A_j)
current_dp_down = 0 # Max length ending A_j, A_k where A_j > A_k (A_k is valley relative to A_j)
# Retrieve the segment trees associated with index j, which contain info about sequences ending at j.
prev_sts = segment_trees[j]
# Handle the base case where j=0. No previous element i exists. Can only form length 2 sequences.
if prev_sts is None:
if A_j < A_k:
current_dp_up = current_base_len
else: # A_j > A_k
current_dp_down = current_base_len
# If j > 0, we can potentially extend sequences ending at j.
else:
st_up_j, st_down_j = prev_sts # Unpack the trees for index j
# Case 1: A_j < A_k. This implies A_k is potentially a peak.
# The previous element A_j must have been a valley relative to (A_i, A_k).
# This requires extending a sequence ending in state `down` at index j.
if A_j < A_k:
# Query max dp_down[i][j] from ST_down[j]. Conditions: i < j, A_i > A_j, and A_i != A_k.
# The query needs to cover ranks corresponding to heights > A_j, excluding A_k.
# Query max length in height range (A_j, A_k) -> ranks (rank_A_j, rank_A_k)
max_val1 = st_down_j.query(rank_A_j + 1, rank_A_k)
# Query max length in height range (A_k, infinity) -> ranks (rank_A_k + 1, D)
max_val2 = st_down_j.query(rank_A_k + 1, D)
# Find the maximum length among valid precursors
best_prev_len = max(max_val1, max_val2)
# If a valid precursor sequence of length >= 2 is found, we can extend it.
if best_prev_len >= 2:
current_dp_up = max(current_base_len, best_prev_len + 1)
else: # Otherwise, the best we can do is start a new sequence of length 2.
current_dp_up = current_base_len
# Case 2: A_j > A_k. This implies A_k is potentially a valley.
# The previous element A_j must have been a peak relative to (A_i, A_k).
# This requires extending a sequence ending in state `up` at index j.
else: # A_j > A_k
# Query max dp_up[i][j] from ST_up[j]. Conditions: i < j, A_i < A_j, and A_i != A_k.
# The query needs to cover ranks corresponding to heights < A_j, excluding A_k.
# Query max length in height range (-infinity, A_k) -> ranks [0, rank_A_k)
max_val1 = st_up_j.query(0, rank_A_k)
# Query max length in height range (A_k, A_j) -> ranks (rank_A_k + 1, rank_A_j)
max_val2 = st_up_j.query(rank_A_k + 1, rank_A_j)
# Find the maximum length among valid precursors
best_prev_len = max(max_val1, max_val2)
# If a valid precursor sequence of length >= 2 is found, extend it.
if best_prev_len >= 2:
current_dp_down = max(current_base_len, best_prev_len + 1)
else: # Otherwise, start a new sequence of length 2.
current_dp_down = current_base_len
# Update segment trees for index k with the computed lengths.
# The update operation stores the max length sequence ending with (A_j, A_k)
# at the position corresponding to rank(A_j) in the trees for k.
if current_dp_up > 0:
st_up_k.update(rank_A_j, current_dp_up)
# If the new length is >= 3, update the overall maximum length found.
if current_dp_up >= 3: max_len = max(max_len, current_dp_up)
if current_dp_down > 0:
st_down_k.update(rank_A_j, current_dp_down)
# Update overall maximum length if >= 3.
if current_dp_down >= 3: max_len = max(max_len, current_dp_down)
# Store the pair of segment trees computed for index k. This information will be used
# for subsequent indices `k' > k` when `k` acts as the second-to-last element `j`.
segment_trees[k] = (st_up_k, st_down_k)
# Final Result: The problem asks for the maximum M.
# Valid M are 0 or M>=3 satisfying conditions.
# If max_len found is less than 3, the maximum valid length is 0.
if max_len < 3:
print(0)
else:
print(max_len)
# Execute the solve function
solve()
qwewe