題目的難度顏色使用 Luogu 上的分級,由簡單到困難分別為 🔴🟠🟡🟢🔵🟣⚫。
Problem Statement
題目簡述
給定 n n n 個區間 [ l i , r i ] [l_i, r_i] [ l i , r i ] ,每個區間 i i i 需選一個整數 w i ∈ [ l i , r i ] w_i \in [l_i, r_i] w i ∈ [ l i , r i ] 。
對於每個 i i i ,判斷是否存在一種選法,使得 w i w_i w i 與所有其他 w j w_j w j (j ≠ i j \ne i j = i ) 都不同。
若存在,輸出 1;否則輸出 0。
Constraints
約束條件
1 ≤ n ≤ 2 ⋅ 1 0 5 1 \leq n \leq 2 \cdot 10^5 1 ≤ n ≤ 2 ⋅ 1 0 5
1 ≤ l i ≤ r i ≤ 2 n 1 \leq l_i \leq r_i \leq 2n 1 ≤ l i ≤ r i ≤ 2 n
思路:前綴和 (Prefix Sum)
關鍵觀察
如果區間 [ l i , r i ] [l_i, r_i] [ l i , r i ] 滿足 l i = r i l_i = r_i l i = r i ,則 w i w_i w i 必須 取值 l i l_i l i ,我們稱此為「固定區間」。
固定區間強佔了它所指向的數值,其他區間若想不與它衝突,就必須避開這個值。
判斷唯一性
設 cnt [ v ] \text{cnt}[v] cnt [ v ] 為數值 v v v 被固定區間覆蓋的次數。
情況 1:固定區間 (
l i = r i l_i = r_i l i = r i )
w i w_i w i 必定為 l i l_i l i 。只有在沒有其他區間也被迫取 l i l_i l i ,即 cnt [ l i ] = = 1 \text{cnt}[l_i] == 1 cnt [ l i ] = = 1 時,i i i 才是唯一的。
情況 2:非固定區間 (
l i < r i l_i < r_i l i < r i )
w i w_i w i 可在 [ l i , r i ] [l_i, r_i] [ l i , r i ] 中任選。只要 ∃ v ∈ [ l i , r i ] \exists\, v \in [l_i, r_i] ∃ v ∈ [ l i , r i ] 使得 cnt [ v ] = 0 \text{cnt}[v] = 0 cnt [ v ] = 0 ,就能讓 w i = v w_i = v w i = v ,且其他非固定區間都能避開 v v v 。
前綴和優化
為了快速查詢「區間 [ l , r ] [l, r] [ l , r ] 內是否有空位」,我們建立前綴和陣列 s s s :
s [ x ] s[x] s [ x ] :數值 0 ∼ x 0 \sim x 0 ∼ x 中,滿足 cnt [ v ] = 0 \text{cnt}[v] = 0 cnt [ v ] = 0 的數量(即空位數量)。
查詢:s [ r ] − s [ l − 1 ] > 0 s[r] - s[l-1] > 0 s [ r ] − s [ l − 1 ] > 0 表示有空位。
約束的利用
由於 1 ≤ l i ≤ r i ≤ 2 n 1 \le l_i \le r_i \le 2n 1 ≤ l i ≤ r i ≤ 2 n ,所有數值都落在 [ 1 , 2 n ] [1, 2n] [ 1 , 2 n ] 範圍內。
因此 cnt \text{cnt} cnt 與 s s s 陣列的大小僅需 O ( n ) O(n) O ( n ) ,確保了整體複雜度為線性。
複雜度分析
時間複雜度:O ( n ) \mathcal{O}(n) O ( n ) ,遍歷區間並用前綴和 O ( 1 ) O(1) O ( 1 ) 查詢。
空間複雜度:O ( n ) \mathcal{O}(n) O ( n ) ,用於存儲 cnt \text{cnt} cnt 與 s s s 陣列(大小為 2 n + 1 2n+1 2 n + 1 )。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from itertools import accumulatedef solve (): n = int (input ()) intervals = [tuple (map (int , input ().split())) for _ in range (n)] assert len (intervals) == n cnt = [0 ] * (2 * n + 1 ) for l, r in intervals: cnt[l] += (l == r) s = list (accumulate(cnt, func=lambda x, y: x + (y == 0 ))) ans = [] for l, r in intervals: if l == r: ans.append('1' if cnt[l] == 1 else '0' ) else : ans.append('1' if s[r] - s[l - 1 ] > 0 else '0' ) print (*ans, sep='' ) if __name__ == "__main__" : t = int (input ()) for _ in range (t): solve()
寫在最後
PROMPT