AtCoder 🔵 ABC381F 1122 Subsequence
題目的難度顏色使用 Luogu 上的分級,由簡單到困難分別為 🔴🟠🟡🟢🔵🟣⚫。
🔗 ABC381F 1122 Subsequence
Problem Statement
題目簡述
給定長度為 的序列 ,請選出一個子序列,使它可以被分成若干相鄰的相同數字對,且每種出現過的數字都恰好出現兩次。求這樣的子序列最大長度。
Constraints
約束條件
- 所有輸入皆為整數
思路:狀態壓縮 DP 維護最早結尾位置
問題本質與突破口
題目要求選出一個 1122 子序列:每種被選中的數字恰好出現兩次,且這兩次必須相鄰構成一個「對」。
注意約束條件,關鍵限制是 ,值域僅 20 種數字,遠小於序列長度 。
由於每種數字只能選擇「不選(0 次)」或「選(2 次)」兩種狀態,我們可以用一個 -bit 的遮罩來表示已選數字的集合。這樣總共有 種狀態,對 DP 來說是可行的。
狀態設計:最早結尾的貪心策略
對於一個已選數字集合 ,在原序列中可能存在多種不同的 1122 子序列選法(相同集合但用不同位置)。我們需要從中選出「最有利於後續擴展」的那一種。
貪心策略的正確性
對於同一個已選集合 ,可能的結尾位置有早有晚。結尾越早,原序列剩餘可用位置越多,後續能加入的數字對也越多。因此對於每個 ,只須記錄最早可能的結尾位置——任何更晚的結尾都不會帶來更好的結果。
- 定義: 表示選取集合 中的數字構成合法 1122 子序列時,該子序列在陣列中的最早結尾位置(0-indexed)。
- 初始狀態:空集合的結尾設為 (代表「序列開頭之前」),其餘狀態初始化為 (代表無窮大,表示尚未找到合法構造)。
轉移:加入一對新數字
假設已知狀態 的最早結尾位置為 ,現在想加入數字 ()形成新狀態 。
加入 的配對必須滿足兩個條件:
- 兩個 的位置都嚴格在 之後(不與已選子序列重疊)
- 與前述的貪心策略類似,這裡選擇最早的兩個 來配對,確保新狀態 的結尾位置盡可能早。
可以預處理每個數字 的出現位置列表,在該列表中找到第一個嚴格大於 的位置,然後再取下一個位置作為配對的第二個元素。這樣就能確定新狀態 的結尾位置。
DP 枚舉順序
由於 ,其數值必定小於 。因此可以按照遞增順序枚舉所有遮罩,保證處理 時所有子狀態的答案已經計算完畢。
若 (即狀態 存在合法構造),則集合大小 為可選取的數字種類數。每種數字貢獻長度 ,故總長度為 。
複雜度分析
- 時間複雜度:,其中 。
- 預處理 ,建立每個元素對應的位置列表;
- DP 枚舉 個狀態,每個狀態遍歷其設定位元(均攤每狀態 ),每次二分搜尋 。
- 空間複雜度:。位置表儲存所有 個索引;DP 陣列大小 。
Code
1 | from bisect import bisect_left |
本部落格所有文章除特別聲明外,均採用CC BY-NC-SA 4.0 授權協議。轉載請註明來源 十六個天亮!
評論
WalineGiscus








