今天依然是上午考 DP,三個小時四道題。
我覺得今天的題目較昨天更簡單。考場上就想出了四個題,但是我以為 T1 \(O(n^3)\) 的做法是暴力,想了好久 T1 也沒想出更好的做法,於是開寫,然後造資料測了測,發現跑得比較快(極限資料應該也是能在我的位置上那臺電腦裡 1s 內過的)。
結果出分是 330,前三題都 100,T4 我的 map 做法有點傻,空間很大,加上寫得劣導致時空消耗大,我被卡到了 30 分。
把在 map 裡重複訪問的東西丟到同一個變數裡,又交了一遍,就有 90 分了。最後一個點空間炸了。
把有一個地方訪問的時候改成了 .count() 防止多開空間,結果最後一個點沒有炸空間了,變成 TLE 了。(好像是這樣的)
都準備寫 FHQ-Treap 了,結果把 map 改成 unordered_map 就過了。
下午講評沒多少內容。開始講的時候大家貌似都改了好多題了。
T1
出題人非常善良地給了圖,可以參考圖來思考。
容易發現如果環上的兩個人碰杯了,那麼他們把這個環分成兩個部分,這兩個部分之間的人互相不能碰杯。
考慮逆時針(順時針也可,但題目是按逆時針給的)地把每個人的酒寫成一個序列,暫時不考慮破環為鏈。發現上面的限制相當於一個區間,區間內的和區間外的人互相不能碰杯。
發現相當於每兩個人形成了一個區間,要選擇一些區間,使得它們要麼為包含關係,要麼不相交。
感覺很像要區間 DP。不用破環為鏈。
注意到區間 DP 裡合法的區間(這裡的區間和前面提到的“每兩個人形成了一個區間”那個區間不是一個東西)長度必須是偶數。所以區間 DP 的最外層和最內層迴圈都[要](還是“可以”?)每次 + 2。而且區間 DP 的三重迴圈列舉到的東西實際上比 \(n ^ 3\) 個少。因此雖然是 \(O(n ^ 3)\),但跑得比較快,[能 \(1 s\) 過 \(n = 1000\) 的資料](?)。
T2
考慮三份權值和相等就是要讓三份的權值和都等於總權值和的 1/3(後面我把它成為 sum / 3)。
我的做法(聽說題解也是這個):
考慮切第一刀的時候,分兩種情況:
- 子樹權值和為 sum / 3,其他部分為 sum / 3 * 2。此時要在其他部分再切一刀,切下一個權值和為 sum / 3 的子樹。
- 子樹權值和為 sum / 3 * 2,其他部分為 sum / 3。此時要在這棵子樹裡再切一刀,切下一個權值和為 sum / 3 的子樹。
樹形 DP 一下就差不多了。第一種情況考慮列舉兩個切下的子樹的根的 LCA,看這個 LCA 的不同子樹。第二種情況我是反過來處理的(先找那個 sum / 3 的,再在它的祖先裡找 sum / 3 * 2 的)。注意寫法和細節,可以見我程式碼。
lr 的做法(感覺更簡潔,但是正確性感覺有點怪,但是用上面的做法來說明好像很對):
遇到 sum / 3 的子樹就直接把它刪掉。
T3
KMP + [線性 DP](?)板子,比較簡單,個人認為是這場最簡單的一道。
T4
模仿 LIS 的 DP 做法。設 \(f _ { i, j }\) 表示最後一個位置是 \(i\),倒數第二個位置是 \(j\) 的最長[斐波那契子序列](?)的長度。
轉移:
要特殊處理子序列長度為 1 和 2 的情況。
直接列舉 \(k\) 不行,由 \(c _ k + c _ j = c _ i\) 得 \(c _ k = c _ i - c _ j\)。於是對每個 \(i\),把 \(c _ j\) 相同的 \(f _ { i, j }\) 丟到一個桶裡取一下 max 即可最佳化轉移。
但是值域太大,於是用 map 之類的。
但是我好傻,沒想到用 map 來做離散化。用 map 離散化的話 map 裡只有 \(n\) 這個級別個數的數。而像我對每個 \(i\) 都開個 map,一共存了 \(n ^ 2\) 級別個數。這導致了空間和時間上都消耗較多。
%%% yt 第一個過 T4,並給我[們](?忘了)講了 map 離散化的做法。
-
今天胡老師還給我們講了怎麼算空間。
-
另外還有一些同學出錯的點。還有我 map 做法掛成 30 分的各種問題。
-
我考場上在草稿本上寫了個檢查的流程。
上面三條來不及整理了,去睡覺了qwq。
2024.8.31