1. 程式人生 > 其它 >3.16 考試總結

3.16 考試總結

3.16 考試總結

這次考試考的不好,原因分以下幾點:

  1. 演算法掌握不夠熟練靈活,實現能力不夠強;
  2. 數學直覺不夠強烈,思維拘泥於死板的傳統信競題中;
  3. 對複雜度和常數的分析不夠精確。

第一個問題,體現在樹剖演算法以及其靈活運用上,

具體來說,樹剖的本質,是用已經預處理好的重鏈,來將任意一條路徑切割成較少的部分,

本場考試中的第一題,我們正是用樹剖對路徑的切割,來代替倍增的跳鏈,從而儘量的減少了重複計算。

同時,在實現能力上,我並沒有思考到高效的實現方式來實現我的思路,

具體來說,在向下跳鏈時,可以先處理出路徑的所有切割點,就能高效準確的向下跳鏈。

這個問題的解決方法只能是多練,多思考演算法的本質以及其核心,

同時在寫程式碼時一定先自己寫,寫完之後可以看別人的優秀實現。

第二個問題,體現在對幾何問題與代數問題的靈活轉化上,

具體來說,從若干二維向量中找到一個,並最大化其與某個給定向量的點積,

這種問題可以抽象成,從平面上的若干個點中選取一個,並最大化斜率給定且過該點的一次函式的截距,

這也是斜率優化演算法的核心,考慮求出所有點形成的上凸殼,即能快速地在凸殼上維護最大答案。

這個問題的解決方法,是多從不同角度思考問題,不要拘泥於固定的思考方法。

第三個問題,具體在對該次考試中第一題的執行效率分析上,

當時認為雙 \(\log\) 的二分倍增雜湊的複雜度正確,卻忽略了演算法常數的問題,

如演算法本身的讀入輸出量大,求倍增時的定址不連續,以及雜湊取模的速度較慢。

對演算法執行的效率的錯誤估計,導致了我沒有繼續想複雜度更優,或者常數更小的做法,

這也成為了阻礙我得到更多分的原因之一。

這個問題的解決辦法,是可以先得到一種恰好要執行一秒的程式,

再在考試電腦上運行同樣的程式,從而得到較為精確的考試電腦的秒執行次數。

接下來寫下對每道題具體做法的總結。

A. string

這道題中,一個好想的思路,是直接二分加雜湊,在二分時需要支援判斷兩路徑串是否相等,

我們可以用樹上 \(k\) 級祖先與樹上最近公共祖先,配合字串雜湊來完成。

暴力的實現是 \(O(q\log^2n)\) 的,但若用 \(O(1)\) \(k\) 級祖先和 \(O(1)\) LCA 就可以做到 \(O(q\log n)\)

但這樣的複雜度很容易卡滿,且常數也較大,是不能通過的。

而實際上我們會發現,在二分以及求路徑雜湊值時,二分與倍增長剖並不是很契合,

即有很多段路徑的雜湊值被我們算了很多次。

那一個自然的思路是嘗試直接倍增跳鏈並判斷,但我們會發現,倍增似乎無法進行往下跳的過程,

但實際上,我們可以在向上跳的時候預處理每一個跳點,就能實現向下跳的過程。

但因為倍增的複雜度很容易卡的比較滿,且在求鏈雜湊值時需要做樹上差分,

而由於樹剖的每一條重鏈所有點的 dfs 序連續,這使得我們可以直接轉化為求序列雜湊值,

故我們也考慮使用樹剖來跳鏈,就能通過本題了。

B. joker

因為看上去除法不如乘法好處理,故我們直接將分母乘上去,

就變成了一個一次函式線性規劃問題,若沒有修改就可以直接維護凸包,做到線性複雜度。

而考慮如果有修改,則我們就可以嘗試維護凸包,使其支援快速修改和查詢。

看上去並沒有什麼好的想法,那就考慮分塊,我們考慮分塊後對每個塊維護凸包。

發現這樣的話,我們修改一個點值,等價於將字尾所有點的橫縱座標分別加上一個偏移量,

而若同一個塊中的所有數都被加上同一個偏移量,則該塊的凸包形狀是不會改變的,

故在修改時,我們暴力重構修改點所在塊,並對後面所有塊打上偏移量標記即可。

而在查詢時,我們需要遍歷每個塊並二分找到答案,那我們設塊大小為 \(B\)

則時間複雜度就是 \(O(N(B+\frac{N\log B}{B}))\),取 \(B=\sqrt{N\log N}\),則總複雜度就是 \(O(N\sqrt{N\log N})\)

注意到取 \(B=\sqrt{N\log N}\) 時會有 \(NB>\frac{N^2\log B}{B}\),故我們稍微將 \(B\) 調小會快一些。

這道題中汲取的經驗有兩點,一是,在做資料結構題且沒思路時可以嘗試使用分塊,

原因是在暴力的修改和查詢的複雜度不平衡時可以用分塊來平衡複雜度,

以及在某些特殊的資訊不具有結合律而無法使用線段樹維護時可以用分塊解決。

C. game

首先可以將異或理解成加一後模二,發現模二不好處理,故我們考慮去掉模二後的問題,發現其與原問題等價。

然後似乎卡住了,我們考慮 SG 函式,因為每個有值的點獨立,故只需考慮一棵只有根有值的樹的 SG 值。

發現一棵只有根有值的樹的 SG 值為 \(2\) 的樹高次方,證明也是簡單的,只需考慮那條連線根和最深葉子的鏈,

故此時我們可以構造出所有 SG 值小於 \(2\) 的樹高次方的後繼,且永無法構造出 SG 值為 \(2\) 的樹高次方的後繼。

此時這題就做完了,只需用桶存 SG 值即可。

這個題汲取的經驗是,思考問題要從多個角度,例如在做博弈論問題時,

不僅要從性質角度思考,也要從 SG 函式角度思考,在沒有思路時也應將表打出來。