1. 程式人生 > >論優化定址時間的重要性

論優化定址時間的重要性

background

冥思苦想。。。 哇!這題我會做!——但時間有點緊!——沒事!打! 1 hour later,碼完了!拍!拍對了!交! “WOC,T70!這。。。”(拍案而起,怒目圓睜) (隔壁一大佬)“誒!我過了!賊快!” “你什麼方法?” “[email protected]#KaTeX parse error: Expected 'EOF', got '#' at position 22: …不是一樣嗎,題解呢?” “[email protected]%&*” “我就是題解法啊!什麼垃圾資料連題解都卡!” “我卡常了的。” “怎麼卡?” “優化一下陣列定址時間!” “QAQ~~”

舉幾個例子

T1 queue

要求支援區間輪換和詢問區間v值出現的個數。(1vn1e5)(1\leq v\leq n\leq 1e5) Time Limit:1s

很不NOIP的方法

輪換相當於點挪動位置 平衡樹先預處理出那些位置要預先開好,然後分每一個v離線處理,時間複雜度O(nlogn)O(n\log n)

很容易想到的方法

K個一塊,每一塊用連結串列維護,順便維護快內每個值出現的次數,輪換的話依然是刪除插入,並將中間每一個塊尾元素挪到後一塊開始。複雜度O(q(K+nK))O(q(K+\frac nK))當K取n\sqrt n

時複雜度為O(qn)O(q\sqrt n) 要不就塊狀連結串列。 雖然複雜度大,但是打得優秀能比部分O(nlogn)O(n\log n)的快!

result

TLE???然而別人過了? 考慮到輪換優化效果不大,那從詢問下手。 每個塊的桶!!桶怎麼開?由於一次詢問是詢問一個值,應該將值放在第一維,塊放在第二維。 結果快了至少300ms。 其實這也要因情況而定,如果修改特別多的話,還不如塊放在第一維好。

其實這點常數優化比較難控制,接下來舉個有代表性的

T2 center

點數nn1e3n\leq 1e3,邊數m(m1e5)(m\leq 1e5)

1e5),詢問數q(q1e5)(q\leq 1e5),對於每個詢問有k組相關的值,每組形如(ui,di)(u_i,d_i),問與uiu_i最短距離不超過did_i的點集並集的大小(k2e6)(k\leq 2e6)。 Time Limit:1.5s -O2 -lm

啊?這要用bitset??

預處理出與點u最短距離不超過d的點集f[u][d]f[u][d],複雜度O(nm+n3ω)O(nm+\frac{n^3}{\omega}) 對於每個詢問直接取並即可複雜度O(knω)O(\frac{\sum kn}{\omega}) 能過

result

哇!又TLE啦! 由於邊是雙向邊,所以預處理的遍歷過程O(nm)O(nm)至少2億次! 在O2的情況下仍然TLE了,why? 你存邊的方式是什麼?陣列模擬連結串列?邊集陣列? 大家可能認為前者的功能很強大?後者需要O(n2)O(n^2)的空間 但是,值得一提的是,後者邊是連續的地址,而前面的是連結串列,要跳來跳去 看起來相差不大,但放大n倍呢? 更改為邊集陣列後不到600ms

後記

其實優化定址複雜度的地方有很多,當一個演算法的時間特別接近時限,但有夢想卡過去時,應當考慮定址時間,不然T成大眾分。