題目大意:給出一個長度為 n 的數列,每個數的取值范圍是 [ 1 , m ],題目保證了每個數至少出現過一次,現在對于 i ∈ [ 1 , m ] ,分別輸出在原數列中,包含了 [ 1 , i ] 的所有種類數字的最短長度
題目分析:剛著手時想了很多做法,但都不能通過數據結構優化到合適的時間復雜度,比如 O( m ) 枚舉數字,每次 O( n ) 去尺取,亦或是 O( m ) 枚舉數字,然后二分長度去 check,越想越離譜。。
其實這個題目已經在提示需要往遞推的方面去想了,先放上官方題解:
簡單來說,當所需要包含數字的范圍確定時 [ 1 , i ] ,那么枚舉每個位置作為左端點或者右端點,相應的一定可以找到與其對應的另一個端點,所以這個題目我們不妨枚舉左端點,然后去確定右端點
設 R[ i ][ l ] 的意義如下:當前需要包含的數字范圍為 [ 1 , i ] ,以點 l 為左端點時,右端點的最小取值
那么顯然對于每個 i 來說,答案就是 min( R[ i ][ 1 ] , R[ i ][ 2 ] , ... , R[ i ][ n ] ) 了
官方題解已經很詳細的說明了如何用線段樹去維護 R 數組了,唯一一點不太清晰的就是如何維護答案,也就是 R[ i ][ l ] - l + 1
本題中需要使用到線段樹的區間修改,也就是需要將某一段區間的值都統一修改為另一個值,那么對于線段樹中的一個節點來說,假設其維護的區間為 [ l , r ] ,如果該區間的值統一被修改為了 x,那么該區間內的答案依次變為了 { x - l + 1 , x - ( l + 1 ) + 1 , ... , x - r + 1},觀察一下這 r - l + 1 個值不難發現,x + 1 是每一項都存在的,唯一不同的就是 減數,又因為我們需要求最小值,所以 減數?取右端點時顯然是最優的,更新這個節點的答案為 ans[ k ] = x - r + 1 即可